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