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