Home | History | Annotate | Download | only in wifi
      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 = 0;
     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 <IpConfiguration> section in minor version 0
    115     private static final Set<String> IP_CONFIGURATION_MINOR_V0_SUPPORTED_TAGS =
    116             new HashSet<String>(Arrays.asList(new String[] {
    117                 IpConfigurationXmlUtil.XML_TAG_IP_ASSIGNMENT,
    118                 IpConfigurationXmlUtil.XML_TAG_LINK_ADDRESS,
    119                 IpConfigurationXmlUtil.XML_TAG_LINK_PREFIX_LENGTH,
    120                 IpConfigurationXmlUtil.XML_TAG_GATEWAY_ADDRESS,
    121                 IpConfigurationXmlUtil.XML_TAG_DNS_SERVER_ADDRESSES,
    122                 IpConfigurationXmlUtil.XML_TAG_PROXY_SETTINGS,
    123                 IpConfigurationXmlUtil.XML_TAG_PROXY_HOST,
    124                 IpConfigurationXmlUtil.XML_TAG_PROXY_PORT,
    125                 IpConfigurationXmlUtil.XML_TAG_PROXY_EXCLUSION_LIST,
    126                 IpConfigurationXmlUtil.XML_TAG_PROXY_PAC_FILE,
    127             }));
    128 
    129     public List<WifiConfiguration> parseNetworkConfigurationsFromXml(XmlPullParser in,
    130             int outerTagDepth, int minorVersion) throws XmlPullParserException, IOException {
    131         // clamp down the minorVersion to the highest one that this parser version supports
    132         if (minorVersion > HIGHEST_SUPPORTED_MINOR_VERSION) {
    133             minorVersion = HIGHEST_SUPPORTED_MINOR_VERSION;
    134         }
    135         // Find the configuration list section.
    136         XmlUtil.gotoNextSectionWithName(in, WifiBackupRestore.XML_TAG_SECTION_HEADER_NETWORK_LIST,
    137                 outerTagDepth);
    138         // Find all the configurations within the configuration list section.
    139         int networkListTagDepth = outerTagDepth + 1;
    140         List<WifiConfiguration> configurations = new ArrayList<>();
    141         while (XmlUtil.gotoNextSectionWithNameOrEnd(
    142                 in, WifiBackupRestore.XML_TAG_SECTION_HEADER_NETWORK, networkListTagDepth)) {
    143             WifiConfiguration configuration =
    144                     parseNetworkConfigurationFromXml(in, minorVersion, networkListTagDepth);
    145             if (configuration != null) {
    146                 Log.v(TAG, "Parsed Configuration: " + configuration.configKey());
    147                 configurations.add(configuration);
    148             }
    149         }
    150         return configurations;
    151     }
    152 
    153     /**
    154      * Parses the configuration data elements from the provided XML stream to a Configuration.
    155      *
    156      * @param in            XmlPullParser instance pointing to the XML stream.
    157      * @param minorVersion  minor version number parsed from incoming data.
    158      * @param outerTagDepth depth of the outer tag in the XML document.
    159      * @return WifiConfiguration object if parsing is successful, null otherwise.
    160      */
    161     private WifiConfiguration parseNetworkConfigurationFromXml(XmlPullParser in, int minorVersion,
    162             int outerTagDepth) throws XmlPullParserException, IOException {
    163         WifiConfiguration configuration = null;
    164         int networkTagDepth = outerTagDepth + 1;
    165         // Retrieve WifiConfiguration object first.
    166         XmlUtil.gotoNextSectionWithName(
    167                 in, WifiBackupRestore.XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION,
    168                 networkTagDepth);
    169         int configTagDepth = networkTagDepth + 1;
    170         configuration = parseWifiConfigurationFromXmlAndValidateConfigKey(in, configTagDepth,
    171                 minorVersion);
    172         if (configuration == null) {
    173             return null;
    174         }
    175         // Now retrieve any IP configuration info.
    176         XmlUtil.gotoNextSectionWithName(
    177                 in, WifiBackupRestore.XML_TAG_SECTION_HEADER_IP_CONFIGURATION, networkTagDepth);
    178         IpConfiguration ipConfiguration = parseIpConfigurationFromXml(in, configTagDepth,
    179                 minorVersion);
    180         configuration.setIpConfiguration(ipConfiguration);
    181         return configuration;
    182     }
    183 
    184     /**
    185      * Helper method to parse the WifiConfiguration object and validate the configKey parsed.
    186      */
    187     private WifiConfiguration parseWifiConfigurationFromXmlAndValidateConfigKey(XmlPullParser in,
    188             int outerTagDepth, int minorVersion) throws XmlPullParserException, IOException {
    189         Pair<String, WifiConfiguration> parsedConfig =
    190                 parseWifiConfigurationFromXml(in, outerTagDepth, minorVersion);
    191         if (parsedConfig == null || parsedConfig.first == null || parsedConfig.second == null) {
    192             return null;
    193         }
    194         String configKeyParsed = parsedConfig.first;
    195         WifiConfiguration configuration = parsedConfig.second;
    196         String configKeyCalculated = configuration.configKey();
    197         if (!configKeyParsed.equals(configKeyCalculated)) {
    198             String configKeyMismatchLog =
    199                     "Configuration key does not match. Retrieved: " + configKeyParsed
    200                             + ", Calculated: " + configKeyCalculated;
    201             if (configuration.shared) {
    202                 Log.e(TAG, configKeyMismatchLog);
    203                 return null;
    204             } else {
    205                 // ConfigKey mismatches are expected for private networks because the
    206                 // UID is not preserved across backup/restore.
    207                 Log.w(TAG, configKeyMismatchLog);
    208             }
    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      */
    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      */
    272     private static Pair<String, WifiConfiguration> parseWifiConfigurationFromXml(XmlPullParser in,
    273             int outerTagDepth, int minorVersion) 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                 default:
    346                     // should never happen, since other tags are filtered out earlier
    347                     throw new XmlPullParserException(
    348                             "Unknown value name found: " + valueName[0]);
    349             }
    350         }
    351         clearAnyKnownIssuesInParsedConfiguration(configuration);
    352         return Pair.create(configKeyInData, configuration);
    353     }
    354 
    355     /**
    356      * Returns a set of supported tags of <WifiConfiguration> element for all minor versions of
    357      * this major version up to and including the specified minorVersion (only adding tags is
    358      * supported in minor versions, removal or changing the meaning of tags requires bumping
    359      * the major version and reseting the minor to 0).
    360      *
    361      * @param minorVersion  minor version number parsed from incoming data.
    362      */
    363     private static Set<String> getSupportedWifiConfigurationTags(int minorVersion) {
    364         switch (minorVersion) {
    365             case 0: return WIFI_CONFIGURATION_MINOR_V0_SUPPORTED_TAGS;
    366             default:
    367                 Log.e(TAG, "Invalid minorVersion: " + minorVersion);
    368                 return Collections.<String>emptySet();
    369         }
    370     }
    371 
    372     /**
    373      * Populate wepKeys array elements only if they were non-empty in the backup data.
    374      *
    375      * @throws XmlPullParserException if parsing errors occur.
    376      */
    377     private static void populateWepKeysFromXmlValue(Object value, String[] wepKeys)
    378             throws XmlPullParserException, IOException {
    379         String[] wepKeysInData = (String[]) value;
    380         if (wepKeysInData == null) {
    381             return;
    382         }
    383         if (wepKeysInData.length != wepKeys.length) {
    384             throw new XmlPullParserException(
    385                     "Invalid Wep Keys length: " + wepKeysInData.length);
    386         }
    387         for (int i = 0; i < wepKeys.length; i++) {
    388             if (wepKeysInData[i].isEmpty()) {
    389                 wepKeys[i] = null;
    390             } else {
    391                 wepKeys[i] = wepKeysInData[i];
    392             }
    393         }
    394     }
    395 
    396     /**
    397      * Parses the IP configuration data elements from the provided XML stream to an
    398      * IpConfiguration object.
    399      *
    400      * @param in            XmlPullParser instance pointing to the XML stream.
    401      * @param outerTagDepth depth of the outer tag in the XML document.
    402      * @param minorVersion  minor version number parsed from incoming data.
    403      * @return IpConfiguration object if parsing is successful, null otherwise.
    404      */
    405     private static IpConfiguration parseIpConfigurationFromXml(XmlPullParser in,
    406             int outerTagDepth, int minorVersion) throws XmlPullParserException, IOException {
    407         // First parse *all* of the tags in <IpConfiguration> section
    408         Set<String> supportedTags = getSupportedIpConfigurationTags(minorVersion);
    409 
    410         String ipAssignmentString = null;
    411         String linkAddressString = null;
    412         Integer linkPrefixLength = null;
    413         String gatewayAddressString = null;
    414         String[] dnsServerAddressesString = null;
    415         String proxySettingsString = null;
    416         String proxyHost = null;
    417         int proxyPort = -1;
    418         String proxyExclusionList = null;
    419         String proxyPacFile = null;
    420 
    421         // Loop through and parse out all the elements from the stream within this section.
    422         while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
    423             String[] valueName = new String[1];
    424             Object value = XmlUtil.readCurrentValue(in, valueName);
    425             String tagName = valueName[0];
    426             if (tagName == null) {
    427                 throw new XmlPullParserException("Missing value name");
    428             }
    429 
    430             // ignore the tags that are not supported up until the current minor version
    431             if (!supportedTags.contains(tagName)) {
    432                 Log.w(TAG, "Unsupported tag + \"" + tagName + "\" found in <IpConfiguration>"
    433                         + " section, ignoring.");
    434                 continue;
    435             }
    436 
    437             // note: the below switch case list should contain all tags supported up until the
    438             // highest minor version supported by this parser
    439             // should any tags be added in next minor versions, conditional processing of them
    440             // also needs to be added in the below code (processing into IpConfiguration object)
    441             switch (tagName) {
    442                 case IpConfigurationXmlUtil.XML_TAG_IP_ASSIGNMENT:
    443                     ipAssignmentString = (String) value;
    444                     break;
    445                 case IpConfigurationXmlUtil.XML_TAG_LINK_ADDRESS:
    446                     linkAddressString = (String) value;
    447                     break;
    448                 case IpConfigurationXmlUtil.XML_TAG_LINK_PREFIX_LENGTH:
    449                     linkPrefixLength = (Integer) value;
    450                     break;
    451                 case IpConfigurationXmlUtil.XML_TAG_GATEWAY_ADDRESS:
    452                     gatewayAddressString = (String) value;
    453                     break;
    454                 case IpConfigurationXmlUtil.XML_TAG_DNS_SERVER_ADDRESSES:
    455                     dnsServerAddressesString = (String[]) value;
    456                     break;
    457                 case IpConfigurationXmlUtil.XML_TAG_PROXY_SETTINGS:
    458                     proxySettingsString = (String) value;
    459                     break;
    460                 case IpConfigurationXmlUtil.XML_TAG_PROXY_HOST:
    461                     proxyHost = (String) value;
    462                     break;
    463                 case IpConfigurationXmlUtil.XML_TAG_PROXY_PORT:
    464                     proxyPort = (int) value;
    465                     break;
    466                 case IpConfigurationXmlUtil.XML_TAG_PROXY_EXCLUSION_LIST:
    467                     proxyExclusionList = (String) value;
    468                     break;
    469                 case IpConfigurationXmlUtil.XML_TAG_PROXY_PAC_FILE:
    470                     proxyPacFile = (String) value;
    471                     break;
    472                 default:
    473                     // should never happen, since other tags are filtered out earlier
    474                     throw new XmlPullParserException(
    475                             "Unknown value name found: " + valueName[0]);
    476             }
    477         }
    478 
    479         // Now process the values into IpConfiguration object
    480         IpConfiguration ipConfiguration = new IpConfiguration();
    481         if (ipAssignmentString == null) {
    482             throw new XmlPullParserException("IpAssignment was missing in IpConfiguration section");
    483         }
    484         IpAssignment ipAssignment = IpAssignment.valueOf(ipAssignmentString);
    485         ipConfiguration.setIpAssignment(ipAssignment);
    486         switch (ipAssignment) {
    487             case STATIC:
    488                 StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();
    489                 if (linkAddressString != null && linkPrefixLength != null) {
    490                     LinkAddress linkAddress = new LinkAddress(
    491                             NetworkUtils.numericToInetAddress(linkAddressString), linkPrefixLength);
    492                     if (linkAddress.getAddress() instanceof Inet4Address) {
    493                         staticIpConfiguration.ipAddress = linkAddress;
    494                     } else {
    495                         Log.w(TAG, "Non-IPv4 address: " + linkAddress);
    496                     }
    497                 }
    498                 if (gatewayAddressString != null) {
    499                     LinkAddress dest = null;
    500                     InetAddress gateway = NetworkUtils.numericToInetAddress(gatewayAddressString);
    501                     RouteInfo route = new RouteInfo(dest, gateway);
    502                     if (route.isIPv4Default()) {
    503                         staticIpConfiguration.gateway = gateway;
    504                     } else {
    505                         Log.w(TAG, "Non-IPv4 default route: " + route);
    506                     }
    507                 }
    508                 if (dnsServerAddressesString != null) {
    509                     for (String dnsServerAddressString : dnsServerAddressesString) {
    510                         InetAddress dnsServerAddress =
    511                                 NetworkUtils.numericToInetAddress(dnsServerAddressString);
    512                         staticIpConfiguration.dnsServers.add(dnsServerAddress);
    513                     }
    514                 }
    515                 ipConfiguration.setStaticIpConfiguration(staticIpConfiguration);
    516                 break;
    517             case DHCP:
    518             case UNASSIGNED:
    519                 break;
    520             default:
    521                 throw new XmlPullParserException("Unknown ip assignment type: " + ipAssignment);
    522         }
    523 
    524         // Process the proxy settings next
    525         if (proxySettingsString == null) {
    526             throw new XmlPullParserException("ProxySettings was missing in"
    527                     + " IpConfiguration section");
    528         }
    529         ProxySettings proxySettings = ProxySettings.valueOf(proxySettingsString);
    530         ipConfiguration.setProxySettings(proxySettings);
    531         switch (proxySettings) {
    532             case STATIC:
    533                 if (proxyHost == null) {
    534                     throw new XmlPullParserException("ProxyHost was missing in"
    535                             + " IpConfiguration section");
    536                 }
    537                 if (proxyPort == -1) {
    538                     throw new XmlPullParserException("ProxyPort was missing in"
    539                             + " IpConfiguration section");
    540                 }
    541                 if (proxyExclusionList == null) {
    542                     throw new XmlPullParserException("ProxyExclusionList was missing in"
    543                             + " IpConfiguration section");
    544                 }
    545                 ipConfiguration.setHttpProxy(
    546                         new ProxyInfo(proxyHost, proxyPort, proxyExclusionList));
    547                 break;
    548             case PAC:
    549                 if (proxyPacFile == null) {
    550                     throw new XmlPullParserException("ProxyPac was missing in"
    551                             + " IpConfiguration section");
    552                 }
    553                 ipConfiguration.setHttpProxy(new ProxyInfo(proxyPacFile));
    554                 break;
    555             case NONE:
    556             case UNASSIGNED:
    557                 break;
    558             default:
    559                 throw new XmlPullParserException(
    560                         "Unknown proxy settings type: " + proxySettings);
    561         }
    562 
    563         return ipConfiguration;
    564     }
    565 
    566     /**
    567      * Returns a set of supported tags of <IpConfiguration> element for all minor versions of
    568      * this major version up to and including the specified minorVersion (only adding tags is
    569      * supported in minor versions, removal or changing the meaning of tags requires bumping
    570      * the major version and reseting the minor to 0).
    571      *
    572      * @param minorVersion  minor version number parsed from incoming data.
    573      */
    574     private static Set<String> getSupportedIpConfigurationTags(int minorVersion) {
    575         switch (minorVersion) {
    576             case 0: return IP_CONFIGURATION_MINOR_V0_SUPPORTED_TAGS;
    577             default:
    578                 Log.e(TAG, "Invalid minorVersion: " + minorVersion);
    579                 return Collections.<String>emptySet();
    580         }
    581     }
    582 }
    583