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