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