Home | History | Annotate | Download | only in wifi
      1 /*
      2  * Copyright (C) 2017 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.wifi.WifiConfiguration;
     21 import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
     22 import android.net.wifi.WifiEnterpriseConfig;
     23 import android.util.Log;
     24 import android.util.Pair;
     25 
     26 import com.android.server.wifi.util.XmlUtil;
     27 import com.android.server.wifi.util.XmlUtil.IpConfigurationXmlUtil;
     28 import com.android.server.wifi.util.XmlUtil.NetworkSelectionStatusXmlUtil;
     29 import com.android.server.wifi.util.XmlUtil.WifiConfigurationXmlUtil;
     30 import com.android.server.wifi.util.XmlUtil.WifiEnterpriseConfigXmlUtil;
     31 
     32 import org.xmlpull.v1.XmlPullParser;
     33 import org.xmlpull.v1.XmlPullParserException;
     34 import org.xmlpull.v1.XmlSerializer;
     35 
     36 import java.io.IOException;
     37 import java.util.ArrayList;
     38 import java.util.List;
     39 
     40 /**
     41  * This class performs serialization and parsing of XML data block that contain the list of WiFi
     42  * network configurations (XML block data inside <NetworkList> tag).
     43  */
     44 public class NetworkListStoreData implements WifiConfigStore.StoreData {
     45     private static final String TAG = "NetworkListStoreData";
     46 
     47     private static final String XML_TAG_SECTION_HEADER_NETWORK_LIST = "NetworkList";
     48     private static final String XML_TAG_SECTION_HEADER_NETWORK = "Network";
     49     private static final String XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION = "WifiConfiguration";
     50     private static final String XML_TAG_SECTION_HEADER_NETWORK_STATUS = "NetworkStatus";
     51     private static final String XML_TAG_SECTION_HEADER_IP_CONFIGURATION = "IpConfiguration";
     52     private static final String XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION =
     53             "WifiEnterpriseConfiguration";
     54 
     55     /**
     56      * List of saved shared networks visible to all the users to be stored in the shared store file.
     57      */
     58     private List<WifiConfiguration> mSharedConfigurations;
     59     /**
     60      * List of saved private networks only visible to the current user to be stored in the user
     61      * specific store file.
     62      */
     63     private List<WifiConfiguration> mUserConfigurations;
     64 
     65     NetworkListStoreData() {}
     66 
     67     @Override
     68     public void serializeData(XmlSerializer out, boolean shared)
     69             throws XmlPullParserException, IOException {
     70         if (shared) {
     71             serializeNetworkList(out, mSharedConfigurations);
     72         } else {
     73             serializeNetworkList(out, mUserConfigurations);
     74         }
     75     }
     76 
     77     @Override
     78     public void deserializeData(XmlPullParser in, int outerTagDepth, boolean shared)
     79             throws XmlPullParserException, IOException {
     80         if (shared) {
     81             mSharedConfigurations = parseNetworkList(in, outerTagDepth);
     82         } else {
     83             mUserConfigurations = parseNetworkList(in, outerTagDepth);
     84         }
     85     }
     86 
     87     @Override
     88     public void resetData(boolean shared) {
     89         if (shared) {
     90             mSharedConfigurations = null;
     91         } else {
     92             mUserConfigurations = null;
     93         }
     94     }
     95 
     96     @Override
     97     public String getName() {
     98         return XML_TAG_SECTION_HEADER_NETWORK_LIST;
     99     }
    100 
    101     @Override
    102     public boolean supportShareData() {
    103         return true;
    104     }
    105 
    106     public void setSharedConfigurations(List<WifiConfiguration> configs) {
    107         mSharedConfigurations = configs;
    108     }
    109 
    110     /**
    111      * An empty list will be returned if no shared configurations.
    112      *
    113      * @return List of {@link WifiConfiguration}
    114      */
    115     public List<WifiConfiguration> getSharedConfigurations() {
    116         if (mSharedConfigurations == null) {
    117             return new ArrayList<WifiConfiguration>();
    118         }
    119         return mSharedConfigurations;
    120     }
    121 
    122     public void setUserConfigurations(List<WifiConfiguration> configs) {
    123         mUserConfigurations = configs;
    124     }
    125 
    126     /**
    127      * An empty list will be returned if no user configurations.
    128      *
    129      * @return List of {@link WifiConfiguration}
    130      */
    131     public List<WifiConfiguration> getUserConfigurations() {
    132         if (mUserConfigurations == null) {
    133             return new ArrayList<WifiConfiguration>();
    134         }
    135         return mUserConfigurations;
    136     }
    137 
    138     /**
    139      * Serialize the list of {@link WifiConfiguration} to an output stream in XML format.
    140      *
    141      * @param out The output stream to serialize the data to
    142      * @param networkList The network list to serialize
    143      * @throws XmlPullParserException
    144      * @throws IOException
    145      */
    146     private void serializeNetworkList(XmlSerializer out, List<WifiConfiguration> networkList)
    147             throws XmlPullParserException, IOException {
    148         if (networkList == null) {
    149             return;
    150         }
    151         for (WifiConfiguration network : networkList) {
    152             serializeNetwork(out, network);
    153         }
    154     }
    155 
    156     /**
    157      * Serialize a {@link WifiConfiguration} to an output stream in XML format.
    158      * @param out
    159      * @param config
    160      * @throws XmlPullParserException
    161      * @throws IOException
    162      */
    163     private void serializeNetwork(XmlSerializer out, WifiConfiguration config)
    164             throws XmlPullParserException, IOException {
    165         XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_NETWORK);
    166 
    167         // Serialize WifiConfiguration.
    168         XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION);
    169         WifiConfigurationXmlUtil.writeToXmlForConfigStore(out, config);
    170         XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION);
    171 
    172         // Serialize network selection status.
    173         XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_NETWORK_STATUS);
    174         NetworkSelectionStatusXmlUtil.writeToXml(out, config.getNetworkSelectionStatus());
    175         XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_NETWORK_STATUS);
    176 
    177         // Serialize IP configuration.
    178         XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_IP_CONFIGURATION);
    179         IpConfigurationXmlUtil.writeToXml(out, config.getIpConfiguration());
    180         XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_IP_CONFIGURATION);
    181 
    182         // Serialize enterprise configuration for enterprise networks.
    183         if (config.enterpriseConfig != null
    184                 && config.enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE) {
    185             XmlUtil.writeNextSectionStart(
    186                     out, XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION);
    187             WifiEnterpriseConfigXmlUtil.writeToXml(out, config.enterpriseConfig);
    188             XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION);
    189         }
    190 
    191         XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_NETWORK);
    192     }
    193 
    194     /**
    195      * Parse a list of {@link WifiConfiguration} from an input stream in XML format.
    196      *
    197      * @param in The input stream to read from
    198      * @param outerTagDepth The XML tag depth of the outer XML block
    199      * @return List of {@link WifiConfiguration}
    200      * @throws XmlPullParserException
    201      * @throws IOException
    202      */
    203     private List<WifiConfiguration> parseNetworkList(XmlPullParser in, int outerTagDepth)
    204             throws XmlPullParserException, IOException {
    205         List<WifiConfiguration> networkList = new ArrayList<>();
    206         while (XmlUtil.gotoNextSectionWithNameOrEnd(in, XML_TAG_SECTION_HEADER_NETWORK,
    207                 outerTagDepth)) {
    208             // Try/catch only runtime exceptions (like illegal args), any XML/IO exceptions are
    209             // fatal and should abort the entire loading process.
    210             try {
    211                 WifiConfiguration config = parseNetwork(in, outerTagDepth + 1);
    212                 networkList.add(config);
    213             } catch (RuntimeException e) {
    214                 // Failed to parse this network, skip it.
    215                 Log.e(TAG, "Failed to parse network config. Skipping...", e);
    216             }
    217         }
    218         return networkList;
    219     }
    220 
    221     /**
    222      * Parse a {@link WifiConfiguration} from an input stream in XML format.
    223      *
    224      * @param in The input stream to read from
    225      * @param outerTagDepth The XML tag depth of the outer XML block
    226      * @return {@link WifiConfiguration}
    227      * @throws XmlPullParserException
    228      * @throws IOException
    229      */
    230     private WifiConfiguration parseNetwork(XmlPullParser in, int outerTagDepth)
    231             throws XmlPullParserException, IOException {
    232         Pair<String, WifiConfiguration> parsedConfig = null;
    233         NetworkSelectionStatus status = null;
    234         IpConfiguration ipConfiguration = null;
    235         WifiEnterpriseConfig enterpriseConfig = null;
    236 
    237         String[] headerName = new String[1];
    238         while (XmlUtil.gotoNextSectionOrEnd(in, headerName, outerTagDepth)) {
    239             switch (headerName[0]) {
    240                 case XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION:
    241                     if (parsedConfig != null) {
    242                         throw new XmlPullParserException("Detected duplicate tag for: "
    243                                 + XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION);
    244                     }
    245                     parsedConfig = WifiConfigurationXmlUtil.parseFromXml(in, outerTagDepth + 1);
    246                     break;
    247                 case XML_TAG_SECTION_HEADER_NETWORK_STATUS:
    248                     if (status != null) {
    249                         throw new XmlPullParserException("Detected duplicate tag for: "
    250                                 + XML_TAG_SECTION_HEADER_NETWORK_STATUS);
    251                     }
    252                     status = NetworkSelectionStatusXmlUtil.parseFromXml(in, outerTagDepth + 1);
    253                     break;
    254                 case XML_TAG_SECTION_HEADER_IP_CONFIGURATION:
    255                     if (ipConfiguration != null) {
    256                         throw new XmlPullParserException("Detected duplicate tag for: "
    257                                 + XML_TAG_SECTION_HEADER_IP_CONFIGURATION);
    258                     }
    259                     ipConfiguration = IpConfigurationXmlUtil.parseFromXml(in, outerTagDepth + 1);
    260                     break;
    261                 case XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION:
    262                     if (enterpriseConfig != null) {
    263                         throw new XmlPullParserException("Detected duplicate tag for: "
    264                                 + XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION);
    265                     }
    266                     enterpriseConfig =
    267                             WifiEnterpriseConfigXmlUtil.parseFromXml(in, outerTagDepth + 1);
    268                     break;
    269                 default:
    270                     throw new XmlPullParserException("Unknown tag under "
    271                             + XML_TAG_SECTION_HEADER_NETWORK + ": " + headerName[0]);
    272             }
    273         }
    274         if (parsedConfig == null || parsedConfig.first == null || parsedConfig.second == null) {
    275             throw new XmlPullParserException("XML parsing of wifi configuration failed");
    276         }
    277         String configKeyParsed = parsedConfig.first;
    278         WifiConfiguration configuration = parsedConfig.second;
    279         String configKeyCalculated = configuration.configKey();
    280         if (!configKeyParsed.equals(configKeyCalculated)) {
    281             throw new XmlPullParserException(
    282                     "Configuration key does not match. Retrieved: " + configKeyParsed
    283                             + ", Calculated: " + configKeyCalculated);
    284         }
    285 
    286         configuration.setNetworkSelectionStatus(status);
    287         configuration.setIpConfiguration(ipConfiguration);
    288         if (enterpriseConfig != null) {
    289             configuration.enterpriseConfig = enterpriseConfig;
    290         }
    291         return configuration;
    292     }
    293 }
    294 
    295