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