1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wifi; 18 19 import android.annotation.Nullable; 20 import android.net.InetAddresses; 21 import android.net.IpConfiguration; 22 import android.net.IpConfiguration.IpAssignment; 23 import android.net.IpConfiguration.ProxySettings; 24 import android.net.LinkAddress; 25 import android.net.ProxyInfo; 26 import android.net.RouteInfo; 27 import android.net.StaticIpConfiguration; 28 import android.net.Uri; 29 import android.net.wifi.SecurityParams; 30 import android.net.wifi.WifiConfiguration; 31 import android.util.Log; 32 import android.util.Pair; 33 34 import com.android.server.wifi.util.XmlUtil; 35 import com.android.server.wifi.util.XmlUtil.IpConfigurationXmlUtil; 36 import com.android.server.wifi.util.XmlUtil.WifiConfigurationXmlUtil; 37 38 import org.xmlpull.v1.XmlPullParser; 39 import org.xmlpull.v1.XmlPullParserException; 40 41 import java.io.IOException; 42 import java.net.Inet4Address; 43 import java.net.InetAddress; 44 import java.util.ArrayList; 45 import java.util.Arrays; 46 import java.util.BitSet; 47 import java.util.Collections; 48 import java.util.HashSet; 49 import java.util.List; 50 import java.util.Locale; 51 import java.util.Set; 52 53 /** 54 * Parser for major version 1 of WiFi backup data. 55 * Contains whitelists of tags for WifiConfiguration and IpConfiguration sections for each of 56 * the minor versions. 57 * 58 * Overall structure of the major version 1 XML schema: 59 * <?xml version='1.0' encoding='utf-8' standalone='yes' ?> 60 * <WifiConfigStore> 61 * <float name="Version" value="1.0" /> 62 * <NetworkList> 63 * <Network> 64 * <WifiConfiguration> 65 * <string name="ConfigKey">value</string> 66 * <string name="SSID">value</string> 67 * <string name="PreSharedKey" />value</string> 68 * <string-array name="WEPKeys" num="4"> 69 * <item value="WifiConfigStoreWep1" /> 70 * <item value="WifiConfigStoreWep2" /> 71 * <item value="WifiConfigStoreWep3" /> 72 * <item value="WifiConfigStoreWep3" /> 73 * </string-array> 74 * ... (other supported tag names in minor version 1: "WEPTxKeyIndex", "HiddenSSID", 75 * "RequirePMF", "AllowedKeyMgmt", "AllowedProtocols", "AllowedAuthAlgos", 76 * "AllowedGroupCiphers", "AllowedPairwiseCiphers", "Shared") 77 * </WifiConfiguration> 78 * <IpConfiguration> 79 * <string name="IpAssignment">value</string> 80 * <string name="ProxySettings">value</string> 81 * ... (other supported tag names in minor version 1: "LinkAddress", "LinkPrefixLength", 82 * "GatewayAddress", "DNSServers", "ProxyHost", "ProxyPort", "ProxyPac", 83 * "ProxyExclusionList") 84 * </IpConfiguration> 85 * </Network> 86 * <Network> 87 * ... (format as above) 88 * </Network> 89 * </NetworkList> 90 * </WifiConfigStore> 91 */ 92 class WifiBackupDataV1Parser implements WifiBackupDataParser { 93 94 private static final String TAG = "WifiBackupDataV1Parser"; 95 96 private static final int HIGHEST_SUPPORTED_MINOR_VERSION = 3; 97 98 // List of tags supported for <WifiConfiguration> section in minor version 0 99 private static final Set<String> WIFI_CONFIGURATION_MINOR_V0_SUPPORTED_TAGS = 100 new HashSet<String>(Arrays.asList(new String[] { 101 WifiConfigurationXmlUtil.XML_TAG_CONFIG_KEY, 102 WifiConfigurationXmlUtil.XML_TAG_SSID, 103 WifiConfigurationXmlUtil.XML_TAG_PRE_SHARED_KEY, 104 WifiConfigurationXmlUtil.XML_TAG_WEP_KEYS, 105 WifiConfigurationXmlUtil.XML_TAG_WEP_TX_KEY_INDEX, 106 WifiConfigurationXmlUtil.XML_TAG_HIDDEN_SSID, 107 WifiConfigurationXmlUtil.XML_TAG_REQUIRE_PMF, 108 WifiConfigurationXmlUtil.XML_TAG_ALLOWED_KEY_MGMT, 109 WifiConfigurationXmlUtil.XML_TAG_ALLOWED_PROTOCOLS, 110 WifiConfigurationXmlUtil.XML_TAG_ALLOWED_AUTH_ALGOS, 111 WifiConfigurationXmlUtil.XML_TAG_ALLOWED_GROUP_CIPHERS, 112 WifiConfigurationXmlUtil.XML_TAG_ALLOWED_PAIRWISE_CIPHERS, 113 WifiConfigurationXmlUtil.XML_TAG_SHARED, 114 })); 115 116 // List of tags supported for <WifiConfiguration> section in minor version 1 117 private static final Set<String> WIFI_CONFIGURATION_MINOR_V1_SUPPORTED_TAGS = 118 new HashSet<String>() {{ 119 addAll(WIFI_CONFIGURATION_MINOR_V0_SUPPORTED_TAGS); 120 add(WifiConfigurationXmlUtil.XML_TAG_METERED_OVERRIDE); 121 }}; 122 123 // List of tags supported for <WifiConfiguration> section in minor version 2 124 private static final Set<String> WIFI_CONFIGURATION_MINOR_V2_SUPPORTED_TAGS = 125 new HashSet<String>() {{ 126 addAll(WIFI_CONFIGURATION_MINOR_V1_SUPPORTED_TAGS); 127 add(WifiConfigurationXmlUtil.XML_TAG_IS_AUTO_JOIN); 128 }}; 129 130 // List of tags supported for <WifiConfiguration> section in minor version 3 131 private static final Set<String> WIFI_CONFIGURATION_MINOR_V3_SUPPORTED_TAGS = 132 new HashSet<String>() {{ 133 addAll(WIFI_CONFIGURATION_MINOR_V2_SUPPORTED_TAGS); 134 add(WifiConfigurationXmlUtil.XML_TAG_SECURITY_PARAMS_LIST); 135 add(WifiConfigurationXmlUtil.XML_TAG_SECURITY_PARAMS); 136 add(WifiConfigurationXmlUtil.XML_TAG_SECURITY_TYPE); 137 add(WifiConfigurationXmlUtil.XML_TAG_SAE_IS_H2E_ONLY_MODE); 138 add(WifiConfigurationXmlUtil.XML_TAG_SAE_IS_PK_ONLY_MODE); 139 add(WifiConfigurationXmlUtil.XML_TAG_IS_ADDED_BY_AUTO_UPGRADE); 140 add(WifiConfigurationXmlUtil.XML_TAG_DELETION_PRIORITY); 141 add(WifiConfigurationXmlUtil.XML_TAG_NUM_REBOOTS_SINCE_LAST_USE); 142 }}; 143 144 // List of tags supported for <IpConfiguration> section in minor version 0 to 3 145 private static final Set<String> IP_CONFIGURATION_MINOR_V0_V1_V2_V3_SUPPORTED_TAGS = 146 new HashSet<String>(Arrays.asList(new String[] { 147 IpConfigurationXmlUtil.XML_TAG_IP_ASSIGNMENT, 148 IpConfigurationXmlUtil.XML_TAG_LINK_ADDRESS, 149 IpConfigurationXmlUtil.XML_TAG_LINK_PREFIX_LENGTH, 150 IpConfigurationXmlUtil.XML_TAG_GATEWAY_ADDRESS, 151 IpConfigurationXmlUtil.XML_TAG_DNS_SERVER_ADDRESSES, 152 IpConfigurationXmlUtil.XML_TAG_PROXY_SETTINGS, 153 IpConfigurationXmlUtil.XML_TAG_PROXY_HOST, 154 IpConfigurationXmlUtil.XML_TAG_PROXY_PORT, 155 IpConfigurationXmlUtil.XML_TAG_PROXY_EXCLUSION_LIST, 156 IpConfigurationXmlUtil.XML_TAG_PROXY_PAC_FILE, 157 })); 158 159 @Override parseNetworkConfigurationsFromXml(XmlPullParser in, int outerTagDepth, int minorVersion)160 public List<WifiConfiguration> parseNetworkConfigurationsFromXml(XmlPullParser in, 161 int outerTagDepth, int minorVersion) throws XmlPullParserException, IOException { 162 // clamp down the minorVersion to the highest one that this parser version supports 163 if (minorVersion > HIGHEST_SUPPORTED_MINOR_VERSION) { 164 minorVersion = HIGHEST_SUPPORTED_MINOR_VERSION; 165 } 166 // Find the configuration list section. 167 XmlUtil.gotoNextSectionWithName(in, WifiBackupRestore.XML_TAG_SECTION_HEADER_NETWORK_LIST, 168 outerTagDepth); 169 // Find all the configurations within the configuration list section. 170 int networkListTagDepth = outerTagDepth + 1; 171 List<WifiConfiguration> configurations = new ArrayList<>(); 172 while (XmlUtil.gotoNextSectionWithNameOrEnd( 173 in, WifiBackupRestore.XML_TAG_SECTION_HEADER_NETWORK, networkListTagDepth)) { 174 WifiConfiguration configuration = 175 parseNetworkConfigurationFromXml(in, minorVersion, networkListTagDepth); 176 if (configuration != null) { 177 Log.v(TAG, "Parsed Configuration: " + configuration.getKey()); 178 configurations.add(configuration); 179 } 180 } 181 return configurations; 182 } 183 184 @Override getHighestSupportedMinorVersion()185 public int getHighestSupportedMinorVersion() { 186 return HIGHEST_SUPPORTED_MINOR_VERSION; 187 } 188 189 /** 190 * Parses the configuration data elements from the provided XML stream to a Configuration. 191 * 192 * @param in XmlPullParser instance pointing to the XML stream. 193 * @param minorVersion minor version number parsed from incoming data. 194 * @param outerTagDepth depth of the outer tag in the XML document. 195 * @return WifiConfiguration object if parsing is successful, null otherwise. 196 */ parseNetworkConfigurationFromXml(XmlPullParser in, int minorVersion, int outerTagDepth)197 private WifiConfiguration parseNetworkConfigurationFromXml(XmlPullParser in, int minorVersion, 198 int outerTagDepth) throws XmlPullParserException, IOException { 199 WifiConfiguration configuration = null; 200 int networkTagDepth = outerTagDepth + 1; 201 // Retrieve WifiConfiguration object first. 202 XmlUtil.gotoNextSectionWithName( 203 in, WifiBackupRestore.XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION, 204 networkTagDepth); 205 int configTagDepth = networkTagDepth + 1; 206 configuration = parseWifiConfigurationFromXml(in, configTagDepth, minorVersion); 207 if (configuration == null) { 208 return null; 209 } 210 // Now retrieve any IP configuration info. 211 XmlUtil.gotoNextSectionWithName( 212 in, WifiBackupRestore.XML_TAG_SECTION_HEADER_IP_CONFIGURATION, networkTagDepth); 213 IpConfiguration ipConfiguration = parseIpConfigurationFromXml(in, configTagDepth, 214 minorVersion); 215 configuration.setIpConfiguration(ipConfiguration); 216 return configuration; 217 } 218 219 /** 220 * Helper method to parse the WifiConfiguration object. 221 */ parseWifiConfigurationFromXml(XmlPullParser in, int outerTagDepth, int minorVersion)222 private WifiConfiguration parseWifiConfigurationFromXml(XmlPullParser in, 223 int outerTagDepth, int minorVersion) throws XmlPullParserException, IOException { 224 Pair<String, WifiConfiguration> parsedConfig = 225 parseWifiConfigurationFromXmlInternal(in, outerTagDepth, minorVersion); 226 if (parsedConfig == null || parsedConfig.first == null || parsedConfig.second == null) { 227 return null; 228 } 229 String configKeyParsed = parsedConfig.first; 230 WifiConfiguration configuration = parsedConfig.second; 231 String configKeyCalculated = configuration.getKey(); 232 if (!configKeyParsed.equals(configKeyCalculated)) { 233 // configKey is not part of the SDK. So, we can't expect this to be the same 234 // across OEM's. Just log a warning & continue. 235 Log.w(TAG, "Configuration key does not match. Retrieved: " + configKeyParsed 236 + ", Calculated: " + configKeyCalculated); 237 } 238 return configuration; 239 } 240 241 /** 242 * Helper method to mask out any invalid data in parsed WifiConfiguration. 243 * 244 * This is a compatibility layer added to the parsing logic to try and weed out any known 245 * issues in the backup data format from other OEM's. 246 */ clearAnyKnownIssuesInParsedConfiguration(WifiConfiguration config)247 private static void clearAnyKnownIssuesInParsedConfiguration(WifiConfiguration config) { 248 /** 249 * Fix for b/73987207. Clear any invalid bits in the bitsets. 250 */ 251 // |allowedKeyManagement| 252 if (config.allowedKeyManagement.length() 253 > WifiConfiguration.KeyMgmt.strings.length) { 254 config.allowedKeyManagement.clear( 255 WifiConfiguration.KeyMgmt.strings.length, 256 config.allowedKeyManagement.length()); 257 } 258 // |allowedProtocols| 259 if (config.allowedProtocols.length() 260 > WifiConfiguration.Protocol.strings.length) { 261 config.allowedProtocols.clear( 262 WifiConfiguration.Protocol.strings.length, 263 config.allowedProtocols.length()); 264 } 265 // |allowedAuthAlgorithms| 266 if (config.allowedAuthAlgorithms.length() 267 > WifiConfiguration.AuthAlgorithm.strings.length) { 268 config.allowedAuthAlgorithms.clear( 269 WifiConfiguration.AuthAlgorithm.strings.length, 270 config.allowedAuthAlgorithms.length()); 271 } 272 // |allowedGroupCiphers| 273 if (config.allowedGroupCiphers.length() 274 > WifiConfiguration.GroupCipher.strings.length) { 275 config.allowedGroupCiphers.clear( 276 WifiConfiguration.GroupCipher.strings.length, 277 config.allowedGroupCiphers.length()); 278 } 279 // |allowedPairwiseCiphers| 280 if (config.allowedPairwiseCiphers.length() 281 > WifiConfiguration.PairwiseCipher.strings.length) { 282 config.allowedPairwiseCiphers.clear( 283 WifiConfiguration.PairwiseCipher.strings.length, 284 config.allowedPairwiseCiphers.length()); 285 } 286 // Add any other fixable issues discovered from other OEM's here. 287 } 288 289 /** 290 * Parses the configuration data elements from the provided XML stream to a 291 * WifiConfiguration object. 292 * Looping through the tags makes it easy to add elements in the future minor versions if 293 * needed. Unsupported elements will be ignored. 294 * 295 * @param in XmlPullParser instance pointing to the XML stream. 296 * @param outerTagDepth depth of the outer tag in the XML document. 297 * @param minorVersion minor version number parsed from incoming data. 298 * @return Pair<Config key, WifiConfiguration object> if parsing is successful, null otherwise. 299 */ parseWifiConfigurationFromXmlInternal( XmlPullParser in, int outerTagDepth, int minorVersion)300 private static Pair<String, WifiConfiguration> parseWifiConfigurationFromXmlInternal( 301 XmlPullParser in, int outerTagDepth, int minorVersion) 302 throws XmlPullParserException, IOException { 303 WifiConfiguration configuration = new WifiConfiguration(); 304 String configKeyInData = null; 305 Set<String> supportedTags = getSupportedWifiConfigurationTags(minorVersion); 306 307 // Loop through and parse out all the elements from the stream within this section. 308 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 309 String tagName = null; 310 Object value = null; 311 if (in.getAttributeValue(null, "name") != null) { 312 String[] valueName = new String[1]; 313 value = XmlUtil.readCurrentValue(in, valueName); 314 tagName = valueName[0]; 315 if (tagName == null) { 316 throw new XmlPullParserException("Missing value name"); 317 } 318 } else { 319 tagName = in.getName(); 320 if (tagName == null) { 321 throw new XmlPullParserException("Unexpected null tag found"); 322 } 323 } 324 325 // ignore the tags that are not supported up until the current minor version 326 if (!supportedTags.contains(tagName)) { 327 Log.w(TAG, "Unsupported tag + \"" + tagName + "\" found in <WifiConfiguration>" 328 + " section, ignoring."); 329 continue; 330 } 331 332 // note: the below switch case list should contain all tags supported up until the 333 // highest minor version supported by this parser 334 switch (tagName) { 335 case WifiConfigurationXmlUtil.XML_TAG_CONFIG_KEY: 336 configKeyInData = (String) value; 337 break; 338 case WifiConfigurationXmlUtil.XML_TAG_SSID: 339 configuration.SSID = (String) value; 340 break; 341 case WifiConfigurationXmlUtil.XML_TAG_PRE_SHARED_KEY: 342 configuration.preSharedKey = (String) value; 343 break; 344 case WifiConfigurationXmlUtil.XML_TAG_WEP_KEYS: 345 populateWepKeysFromXmlValue(value, configuration.wepKeys); 346 break; 347 case WifiConfigurationXmlUtil.XML_TAG_WEP_TX_KEY_INDEX: 348 configuration.wepTxKeyIndex = (int) value; 349 break; 350 case WifiConfigurationXmlUtil.XML_TAG_HIDDEN_SSID: 351 configuration.hiddenSSID = (boolean) value; 352 break; 353 case WifiConfigurationXmlUtil.XML_TAG_REQUIRE_PMF: 354 configuration.requirePmf = (boolean) value; 355 break; 356 case WifiConfigurationXmlUtil.XML_TAG_ALLOWED_KEY_MGMT: 357 byte[] allowedKeyMgmt = (byte[]) value; 358 configuration.allowedKeyManagement = BitSet.valueOf(allowedKeyMgmt); 359 break; 360 case WifiConfigurationXmlUtil.XML_TAG_ALLOWED_PROTOCOLS: 361 byte[] allowedProtocols = (byte[]) value; 362 configuration.allowedProtocols = BitSet.valueOf(allowedProtocols); 363 break; 364 case WifiConfigurationXmlUtil.XML_TAG_ALLOWED_AUTH_ALGOS: 365 byte[] allowedAuthAlgorithms = (byte[]) value; 366 configuration.allowedAuthAlgorithms = BitSet.valueOf(allowedAuthAlgorithms); 367 break; 368 case WifiConfigurationXmlUtil.XML_TAG_ALLOWED_GROUP_CIPHERS: 369 byte[] allowedGroupCiphers = (byte[]) value; 370 configuration.allowedGroupCiphers = BitSet.valueOf(allowedGroupCiphers); 371 break; 372 case WifiConfigurationXmlUtil.XML_TAG_ALLOWED_PAIRWISE_CIPHERS: 373 byte[] allowedPairwiseCiphers = (byte[]) value; 374 configuration.allowedPairwiseCiphers = 375 BitSet.valueOf(allowedPairwiseCiphers); 376 break; 377 case WifiConfigurationXmlUtil.XML_TAG_SHARED: 378 configuration.shared = (boolean) value; 379 break; 380 case WifiConfigurationXmlUtil.XML_TAG_METERED_OVERRIDE: 381 configuration.meteredOverride = (int) value; 382 break; 383 case WifiConfigurationXmlUtil.XML_TAG_IS_AUTO_JOIN: 384 configuration.allowAutojoin = (boolean) value; 385 break; 386 case WifiConfigurationXmlUtil.XML_TAG_DELETION_PRIORITY: 387 configuration.setDeletionPriority((int) value); 388 break; 389 case WifiConfigurationXmlUtil.XML_TAG_NUM_REBOOTS_SINCE_LAST_USE: 390 configuration.numRebootsSinceLastUse = (int) value; 391 break; 392 case WifiConfigurationXmlUtil.XML_TAG_SECURITY_PARAMS_LIST: 393 parseSecurityParamsListFromXml(in, outerTagDepth + 1, configuration); 394 break; 395 default: 396 // should never happen, since other tags are filtered out earlier 397 throw new XmlPullParserException( 398 "Unknown value name found: " + tagName); 399 } 400 } 401 clearAnyKnownIssuesInParsedConfiguration(configuration); 402 return Pair.create(configKeyInData, configuration); 403 } 404 405 /** 406 * Returns a set of supported tags of <WifiConfiguration> element for all minor versions of 407 * this major version up to and including the specified minorVersion (only adding tags is 408 * supported in minor versions, removal or changing the meaning of tags requires bumping 409 * the major version and reseting the minor to 0). 410 * 411 * @param minorVersion minor version number parsed from incoming data. 412 */ getSupportedWifiConfigurationTags(int minorVersion)413 private static Set<String> getSupportedWifiConfigurationTags(int minorVersion) { 414 switch (minorVersion) { 415 case 0: 416 return WIFI_CONFIGURATION_MINOR_V0_SUPPORTED_TAGS; 417 case 1: 418 return WIFI_CONFIGURATION_MINOR_V1_SUPPORTED_TAGS; 419 case 2: 420 return WIFI_CONFIGURATION_MINOR_V2_SUPPORTED_TAGS; 421 case 3: 422 return WIFI_CONFIGURATION_MINOR_V3_SUPPORTED_TAGS; 423 default: 424 Log.e(TAG, "Invalid minorVersion: " + minorVersion); 425 return Collections.<String>emptySet(); 426 } 427 } 428 429 /** 430 * Populate wepKeys array elements only if they were non-empty in the backup data. 431 * 432 * @throws XmlPullParserException if parsing errors occur. 433 */ populateWepKeysFromXmlValue(Object value, String[] wepKeys)434 private static void populateWepKeysFromXmlValue(Object value, String[] wepKeys) 435 throws XmlPullParserException, IOException { 436 String[] wepKeysInData = (String[]) value; 437 if (wepKeysInData == null) { 438 return; 439 } 440 if (wepKeysInData.length != wepKeys.length) { 441 throw new XmlPullParserException( 442 "Invalid Wep Keys length: " + wepKeysInData.length); 443 } 444 for (int i = 0; i < wepKeys.length; i++) { 445 if (wepKeysInData[i].isEmpty()) { 446 wepKeys[i] = null; 447 } else { 448 wepKeys[i] = wepKeysInData[i]; 449 } 450 } 451 } 452 parseSecurityParamsFromXml( XmlPullParser in, int outerTagDepth)453 private static SecurityParams parseSecurityParamsFromXml( 454 XmlPullParser in, int outerTagDepth) throws XmlPullParserException, IOException { 455 SecurityParams params = null; 456 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 457 String[] valueName = new String[1]; 458 Object value = XmlUtil.readCurrentValue(in, valueName); 459 String tagName = valueName[0]; 460 if (tagName == null) { 461 throw new XmlPullParserException("Missing value name"); 462 } 463 switch (tagName) { 464 case WifiConfigurationXmlUtil.XML_TAG_SECURITY_TYPE: 465 params = SecurityParams.createSecurityParamsBySecurityType((int) value); 466 break; 467 case WifiConfigurationXmlUtil.XML_TAG_SAE_IS_H2E_ONLY_MODE: 468 if (null == params) throw new XmlPullParserException("Missing security type."); 469 params.enableSaeH2eOnlyMode((boolean) value); 470 break; 471 case WifiConfigurationXmlUtil.XML_TAG_SAE_IS_PK_ONLY_MODE: 472 if (null == params) throw new XmlPullParserException("Missing security type."); 473 params.enableSaePkOnlyMode((boolean) value); 474 break; 475 case WifiConfigurationXmlUtil.XML_TAG_IS_ADDED_BY_AUTO_UPGRADE: 476 if (null == params) throw new XmlPullParserException("Missing security type."); 477 params.setIsAddedByAutoUpgrade((boolean) value); 478 break; 479 } 480 } 481 return params; 482 } 483 484 /** 485 * Populate security params list elements only if they were non-empty in the backup data. 486 * 487 * @throws XmlPullParserException if parsing errors occur. 488 */ parseSecurityParamsListFromXml( XmlPullParser in, int outerTagDepth, WifiConfiguration configuration)489 private static void parseSecurityParamsListFromXml( 490 XmlPullParser in, int outerTagDepth, 491 WifiConfiguration configuration) 492 throws XmlPullParserException, IOException { 493 494 List<SecurityParams> paramsList = new ArrayList<>(); 495 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 496 switch (in.getName()) { 497 case WifiConfigurationXmlUtil.XML_TAG_SECURITY_PARAMS: 498 SecurityParams params = parseSecurityParamsFromXml(in, outerTagDepth + 1); 499 if (params != null) { 500 paramsList.add(params); 501 } 502 break; 503 } 504 } 505 if (!paramsList.isEmpty()) { 506 configuration.setSecurityParams(paramsList); 507 } 508 } 509 parseProxyExclusionListString( @ullable String exclusionListString)510 private static List<String> parseProxyExclusionListString( 511 @Nullable String exclusionListString) { 512 if (exclusionListString == null) { 513 return Collections.emptyList(); 514 } else { 515 return Arrays.asList(exclusionListString.toLowerCase(Locale.ROOT).split(",")); 516 } 517 } 518 519 /** 520 * Parses the IP configuration data elements from the provided XML stream to an 521 * IpConfiguration object. 522 * 523 * @param in XmlPullParser instance pointing to the XML stream. 524 * @param outerTagDepth depth of the outer tag in the XML document. 525 * @param minorVersion minor version number parsed from incoming data. 526 * @return IpConfiguration object if parsing is successful, null otherwise. 527 */ parseIpConfigurationFromXml(XmlPullParser in, int outerTagDepth, int minorVersion)528 private static IpConfiguration parseIpConfigurationFromXml(XmlPullParser in, 529 int outerTagDepth, int minorVersion) throws XmlPullParserException, IOException { 530 // First parse *all* of the tags in <IpConfiguration> section 531 Set<String> supportedTags = getSupportedIpConfigurationTags(minorVersion); 532 533 String ipAssignmentString = null; 534 String linkAddressString = null; 535 Integer linkPrefixLength = null; 536 String gatewayAddressString = null; 537 String[] dnsServerAddressesString = null; 538 String proxySettingsString = null; 539 String proxyHost = null; 540 int proxyPort = -1; 541 String proxyExclusionList = null; 542 String proxyPacFile = null; 543 544 // Loop through and parse out all the elements from the stream within this section. 545 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 546 String[] valueName = new String[1]; 547 Object value = XmlUtil.readCurrentValue(in, valueName); 548 String tagName = valueName[0]; 549 if (tagName == null) { 550 throw new XmlPullParserException("Missing value name"); 551 } 552 553 // ignore the tags that are not supported up until the current minor version 554 if (!supportedTags.contains(tagName)) { 555 Log.w(TAG, "Unsupported tag + \"" + tagName + "\" found in <IpConfiguration>" 556 + " section, ignoring."); 557 continue; 558 } 559 560 // note: the below switch case list should contain all tags supported up until the 561 // highest minor version supported by this parser 562 // should any tags be added in next minor versions, conditional processing of them 563 // also needs to be added in the below code (processing into IpConfiguration object) 564 switch (tagName) { 565 case IpConfigurationXmlUtil.XML_TAG_IP_ASSIGNMENT: 566 ipAssignmentString = (String) value; 567 break; 568 case IpConfigurationXmlUtil.XML_TAG_LINK_ADDRESS: 569 linkAddressString = (String) value; 570 break; 571 case IpConfigurationXmlUtil.XML_TAG_LINK_PREFIX_LENGTH: 572 linkPrefixLength = (Integer) value; 573 break; 574 case IpConfigurationXmlUtil.XML_TAG_GATEWAY_ADDRESS: 575 gatewayAddressString = (String) value; 576 break; 577 case IpConfigurationXmlUtil.XML_TAG_DNS_SERVER_ADDRESSES: 578 dnsServerAddressesString = (String[]) value; 579 break; 580 case IpConfigurationXmlUtil.XML_TAG_PROXY_SETTINGS: 581 proxySettingsString = (String) value; 582 break; 583 case IpConfigurationXmlUtil.XML_TAG_PROXY_HOST: 584 proxyHost = (String) value; 585 break; 586 case IpConfigurationXmlUtil.XML_TAG_PROXY_PORT: 587 proxyPort = (int) value; 588 break; 589 case IpConfigurationXmlUtil.XML_TAG_PROXY_EXCLUSION_LIST: 590 proxyExclusionList = (String) value; 591 break; 592 case IpConfigurationXmlUtil.XML_TAG_PROXY_PAC_FILE: 593 proxyPacFile = (String) value; 594 break; 595 default: 596 // should never happen, since other tags are filtered out earlier 597 throw new XmlPullParserException( 598 "Unknown value name found: " + valueName[0]); 599 } 600 } 601 602 // Now process the values into IpConfiguration object 603 IpConfiguration ipConfiguration = new IpConfiguration(); 604 if (ipAssignmentString == null) { 605 throw new XmlPullParserException("IpAssignment was missing in IpConfiguration section"); 606 } 607 IpAssignment ipAssignment = IpAssignment.valueOf(ipAssignmentString); 608 ipConfiguration.setIpAssignment(ipAssignment); 609 switch (ipAssignment) { 610 case STATIC: 611 StaticIpConfiguration.Builder builder = new StaticIpConfiguration.Builder(); 612 if (linkAddressString != null && linkPrefixLength != null) { 613 LinkAddress linkAddress = new LinkAddress( 614 InetAddresses.parseNumericAddress(linkAddressString), linkPrefixLength); 615 if (linkAddress.getAddress() instanceof Inet4Address) { 616 builder.setIpAddress(linkAddress); 617 } else { 618 Log.w(TAG, "Non-IPv4 address: " + linkAddress); 619 } 620 } 621 if (gatewayAddressString != null) { 622 InetAddress gateway = InetAddresses.parseNumericAddress(gatewayAddressString); 623 RouteInfo route = new RouteInfo(null, gateway, null, RouteInfo.RTN_UNICAST); 624 if (route.isDefaultRoute() 625 && route.getDestination().getAddress() instanceof Inet4Address) { 626 builder.setGateway(gateway); 627 } else { 628 Log.w(TAG, "Non-IPv4 default route: " + route); 629 } 630 } 631 if (dnsServerAddressesString != null) { 632 List<InetAddress> dnsServerAddresses = new ArrayList<>(); 633 for (String dnsServerAddressString : dnsServerAddressesString) { 634 InetAddress dnsServerAddress = 635 InetAddresses.parseNumericAddress(dnsServerAddressString); 636 dnsServerAddresses.add(dnsServerAddress); 637 } 638 builder.setDnsServers(dnsServerAddresses); 639 } 640 ipConfiguration.setStaticIpConfiguration(builder.build()); 641 break; 642 case DHCP: 643 case UNASSIGNED: 644 break; 645 default: 646 throw new XmlPullParserException("Unknown ip assignment type: " + ipAssignment); 647 } 648 649 // Process the proxy settings next 650 if (proxySettingsString == null) { 651 throw new XmlPullParserException("ProxySettings was missing in" 652 + " IpConfiguration section"); 653 } 654 ProxySettings proxySettings = ProxySettings.valueOf(proxySettingsString); 655 ipConfiguration.setProxySettings(proxySettings); 656 switch (proxySettings) { 657 case STATIC: 658 if (proxyHost == null) { 659 throw new XmlPullParserException("ProxyHost was missing in" 660 + " IpConfiguration section"); 661 } 662 if (proxyPort == -1) { 663 throw new XmlPullParserException("ProxyPort was missing in" 664 + " IpConfiguration section"); 665 } 666 if (proxyExclusionList == null) { 667 throw new XmlPullParserException("ProxyExclusionList was missing in" 668 + " IpConfiguration section"); 669 } 670 ipConfiguration.setHttpProxy( 671 ProxyInfo.buildDirectProxy( 672 proxyHost, proxyPort, 673 parseProxyExclusionListString(proxyExclusionList))); 674 break; 675 case PAC: 676 if (proxyPacFile == null) { 677 throw new XmlPullParserException("ProxyPac was missing in" 678 + " IpConfiguration section"); 679 } 680 ipConfiguration.setHttpProxy( 681 ProxyInfo.buildPacProxy(Uri.parse(proxyPacFile))); 682 break; 683 case NONE: 684 case UNASSIGNED: 685 break; 686 default: 687 throw new XmlPullParserException( 688 "Unknown proxy settings type: " + proxySettings); 689 } 690 691 return ipConfiguration; 692 } 693 694 /** 695 * Returns a set of supported tags of <IpConfiguration> element for all minor versions of 696 * this major version up to and including the specified minorVersion (only adding tags is 697 * supported in minor versions, removal or changing the meaning of tags requires bumping 698 * the major version and reseting the minor to 0). 699 * 700 * @param minorVersion minor version number parsed from incoming data. 701 */ getSupportedIpConfigurationTags(int minorVersion)702 private static Set<String> getSupportedIpConfigurationTags(int minorVersion) { 703 switch (minorVersion) { 704 case 0: 705 case 1: 706 case 2: 707 case 3: 708 return IP_CONFIGURATION_MINOR_V0_V1_V2_V3_SUPPORTED_TAGS; 709 default: 710 Log.e(TAG, "Invalid minorVersion: " + minorVersion); 711 return Collections.<String>emptySet(); 712 } 713 } 714 } 715