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