1 /*
2  * Copyright (C) 2016 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.util;
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.MacAddress;
24 import android.net.NetworkUtils;
25 import android.net.ProxyInfo;
26 import android.net.RouteInfo;
27 import android.net.StaticIpConfiguration;
28 import android.net.wifi.WifiConfiguration;
29 import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
30 import android.net.wifi.WifiEnterpriseConfig;
31 import android.util.Log;
32 import android.util.Pair;
33 
34 import com.android.internal.util.XmlUtils;
35 
36 import org.xmlpull.v1.XmlPullParser;
37 import org.xmlpull.v1.XmlPullParserException;
38 import org.xmlpull.v1.XmlSerializer;
39 
40 import java.io.IOException;
41 import java.net.Inet4Address;
42 import java.net.InetAddress;
43 import java.util.Arrays;
44 import java.util.BitSet;
45 import java.util.HashMap;
46 
47 /**
48  * Utils for manipulating XML data. This is essentially a wrapper over XmlUtils provided by core.
49  * The utility provides methods to write/parse section headers and write/parse values.
50  * This utility is designed for formatting the XML into the following format:
51  * <Document Header>
52  *  <Section 1 Header>
53  *   <Value 1>
54  *   <Value 2>
55  *   ...
56  *   <Sub Section 1 Header>
57  *    <Value 1>
58  *    <Value 2>
59  *    ...
60  *   </Sub Section 1 Header>
61  *  </Section 1 Header>
62  * </Document Header>
63  *
64  * Note: These utility methods are meant to be used for:
65  * 1. Backup/restore wifi network data to/from cloud.
66  * 2. Persisting wifi network data to/from disk.
67  */
68 public class XmlUtil {
69     private static final String TAG = "WifiXmlUtil";
70 
71     /**
72      * Ensure that the XML stream is at a start tag or the end of document.
73      *
74      * @throws XmlPullParserException if parsing errors occur.
75      */
gotoStartTag(XmlPullParser in)76     private static void gotoStartTag(XmlPullParser in)
77             throws XmlPullParserException, IOException {
78         int type = in.getEventType();
79         while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) {
80             type = in.next();
81         }
82     }
83 
84     /**
85      * Ensure that the XML stream is at an end tag or the end of document.
86      *
87      * @throws XmlPullParserException if parsing errors occur.
88      */
gotoEndTag(XmlPullParser in)89     private static void gotoEndTag(XmlPullParser in)
90             throws XmlPullParserException, IOException {
91         int type = in.getEventType();
92         while (type != XmlPullParser.END_TAG && type != XmlPullParser.END_DOCUMENT) {
93             type = in.next();
94         }
95     }
96 
97     /**
98      * Start processing the XML stream at the document header.
99      *
100      * @param in         XmlPullParser instance pointing to the XML stream.
101      * @param headerName expected name for the start tag.
102      * @throws XmlPullParserException if parsing errors occur.
103      */
gotoDocumentStart(XmlPullParser in, String headerName)104     public static void gotoDocumentStart(XmlPullParser in, String headerName)
105             throws XmlPullParserException, IOException {
106         XmlUtils.beginDocument(in, headerName);
107     }
108 
109     /**
110      * Move the XML stream to the next section header or indicate if there are no more sections.
111      * The provided outerDepth is used to find sub sections within that depth.
112      *
113      * Use this to move across sections if the ordering of sections are variable. The returned name
114      * can be used to decide what section is next.
115      *
116      * @param in         XmlPullParser instance pointing to the XML stream.
117      * @param headerName An array of one string, used to return the name of the next section.
118      * @param outerDepth Find section within this depth.
119      * @return {@code true} if a next section is found, {@code false} if there are no more sections.
120      * @throws XmlPullParserException if parsing errors occur.
121      */
gotoNextSectionOrEnd( XmlPullParser in, String[] headerName, int outerDepth)122     public static boolean gotoNextSectionOrEnd(
123             XmlPullParser in, String[] headerName, int outerDepth)
124             throws XmlPullParserException, IOException {
125         if (XmlUtils.nextElementWithin(in, outerDepth)) {
126             headerName[0] = in.getName();
127             return true;
128         }
129         return false;
130     }
131 
132     /**
133      * Move the XML stream to the next section header or indicate if there are no more sections.
134      * If a section, exists ensure that the name matches the provided name.
135      * The provided outerDepth is used to find sub sections within that depth.
136      *
137      * Use this to move across repeated sections until the end.
138      *
139      * @param in           XmlPullParser instance pointing to the XML stream.
140      * @param expectedName expected name for the section header.
141      * @param outerDepth   Find section within this depth.
142      * @return {@code true} if a next section is found, {@code false} if there are no more sections.
143      * @throws XmlPullParserException if the section header name does not match |expectedName|,
144      *                                or if parsing errors occur.
145      */
gotoNextSectionWithNameOrEnd( XmlPullParser in, String expectedName, int outerDepth)146     public static boolean gotoNextSectionWithNameOrEnd(
147             XmlPullParser in, String expectedName, int outerDepth)
148             throws XmlPullParserException, IOException {
149         String[] headerName = new String[1];
150         if (gotoNextSectionOrEnd(in, headerName, outerDepth)) {
151             if (headerName[0].equals(expectedName)) {
152                 return true;
153             }
154             throw new XmlPullParserException(
155                     "Next section name does not match expected name: " + expectedName);
156         }
157         return false;
158     }
159 
160     /**
161      * Move the XML stream to the next section header and ensure that the name matches the provided
162      * name.
163      * The provided outerDepth is used to find sub sections within that depth.
164      *
165      * Use this to move across sections if the ordering of sections are fixed.
166      *
167      * @param in           XmlPullParser instance pointing to the XML stream.
168      * @param expectedName expected name for the section header.
169      * @param outerDepth   Find section within this depth.
170      * @throws XmlPullParserException if the section header name does not match |expectedName|,
171      *                                there are no more sections or if parsing errors occur.
172      */
gotoNextSectionWithName( XmlPullParser in, String expectedName, int outerDepth)173     public static void gotoNextSectionWithName(
174             XmlPullParser in, String expectedName, int outerDepth)
175             throws XmlPullParserException, IOException {
176         if (!gotoNextSectionWithNameOrEnd(in, expectedName, outerDepth)) {
177             throw new XmlPullParserException("Section not found. Expected: " + expectedName);
178         }
179     }
180 
181     /**
182      * Checks if the stream is at the end of a section of values. This moves the stream to next tag
183      * and checks if it finds an end tag at the specified depth.
184      *
185      * @param in           XmlPullParser instance pointing to the XML stream.
186      * @param sectionDepth depth of the start tag of this section. Used to match the end tag.
187      * @return {@code true} if a end tag at the provided depth is found, {@code false} otherwise
188      * @throws XmlPullParserException if parsing errors occur.
189      */
isNextSectionEnd(XmlPullParser in, int sectionDepth)190     public static boolean isNextSectionEnd(XmlPullParser in, int sectionDepth)
191             throws XmlPullParserException, IOException {
192         return !XmlUtils.nextElementWithin(in, sectionDepth);
193     }
194 
195     /**
196      * Read the current value in the XML stream using core XmlUtils and stores the retrieved
197      * value name in the string provided. This method reads the value contained in current start
198      * tag.
199      * Note: Because there could be genuine null values being read from the XML, this method raises
200      * an exception to indicate errors.
201      *
202      * @param in        XmlPullParser instance pointing to the XML stream.
203      * @param valueName An array of one string, used to return the name attribute
204      *                  of the value's tag.
205      * @return value retrieved from the XML stream.
206      * @throws XmlPullParserException if parsing errors occur.
207      */
readCurrentValue(XmlPullParser in, String[] valueName)208     public static Object readCurrentValue(XmlPullParser in, String[] valueName)
209             throws XmlPullParserException, IOException {
210         Object value = XmlUtils.readValueXml(in, valueName);
211         // XmlUtils.readValue does not always move the stream to the end of the tag. So, move
212         // it to the end tag before returning from here.
213         gotoEndTag(in);
214         return value;
215     }
216 
217     /**
218      * Read the next value in the XML stream using core XmlUtils and ensure that it matches the
219      * provided name. This method moves the stream to the next start tag and reads the value
220      * contained in it.
221      * Note: Because there could be genuine null values being read from the XML, this method raises
222      * an exception to indicate errors.
223      *
224      * @param in XmlPullParser instance pointing to the XML stream.
225      * @return value retrieved from the XML stream.
226      * @throws XmlPullParserException if the value read does not match |expectedName|,
227      *                                or if parsing errors occur.
228      */
readNextValueWithName(XmlPullParser in, String expectedName)229     public static Object readNextValueWithName(XmlPullParser in, String expectedName)
230             throws XmlPullParserException, IOException {
231         String[] valueName = new String[1];
232         XmlUtils.nextElement(in);
233         Object value = readCurrentValue(in, valueName);
234         if (valueName[0].equals(expectedName)) {
235             return value;
236         }
237         throw new XmlPullParserException(
238                 "Value not found. Expected: " + expectedName + ", but got: " + valueName[0]);
239     }
240 
241     /**
242      * Write the XML document start with the provided document header name.
243      *
244      * @param out        XmlSerializer instance pointing to the XML stream.
245      * @param headerName name for the start tag.
246      */
writeDocumentStart(XmlSerializer out, String headerName)247     public static void writeDocumentStart(XmlSerializer out, String headerName)
248             throws IOException {
249         out.startDocument(null, true);
250         out.startTag(null, headerName);
251     }
252 
253     /**
254      * Write the XML document end with the provided document header name.
255      *
256      * @param out        XmlSerializer instance pointing to the XML stream.
257      * @param headerName name for the end tag.
258      */
writeDocumentEnd(XmlSerializer out, String headerName)259     public static void writeDocumentEnd(XmlSerializer out, String headerName)
260             throws IOException {
261         out.endTag(null, headerName);
262         out.endDocument();
263     }
264 
265     /**
266      * Write a section start header tag with the provided section name.
267      *
268      * @param out        XmlSerializer instance pointing to the XML stream.
269      * @param headerName name for the start tag.
270      */
writeNextSectionStart(XmlSerializer out, String headerName)271     public static void writeNextSectionStart(XmlSerializer out, String headerName)
272             throws IOException {
273         out.startTag(null, headerName);
274     }
275 
276     /**
277      * Write a section end header tag with the provided section name.
278      *
279      * @param out        XmlSerializer instance pointing to the XML stream.
280      * @param headerName name for the end tag.
281      */
writeNextSectionEnd(XmlSerializer out, String headerName)282     public static void writeNextSectionEnd(XmlSerializer out, String headerName)
283             throws IOException {
284         out.endTag(null, headerName);
285     }
286 
287     /**
288      * Write the value with the provided name in the XML stream using core XmlUtils.
289      *
290      * @param out   XmlSerializer instance pointing to the XML stream.
291      * @param name  name of the value.
292      * @param value value to be written.
293      */
writeNextValue(XmlSerializer out, String name, Object value)294     public static void writeNextValue(XmlSerializer out, String name, Object value)
295             throws XmlPullParserException, IOException {
296         XmlUtils.writeValueXml(value, name, out);
297     }
298 
299     /**
300      * Utility class to serialize and deserialize {@link WifiConfiguration} object to XML &
301      * vice versa.
302      * This is used by both {@link com.android.server.wifi.WifiConfigStore} &
303      * {@link com.android.server.wifi.WifiBackupRestore} modules.
304      * The |writeConfigurationToXml| has 2 versions, one for backup and one for config store.
305      * There is only 1 version of |parseXmlToConfiguration| for both backup & config store.
306      * The parse method is written so that any element added/deleted in future revisions can
307      * be easily handled.
308      */
309     public static class WifiConfigurationXmlUtil {
310         /**
311          * List of XML tags corresponding to WifiConfiguration object elements.
312          */
313         public static final String XML_TAG_SSID = "SSID";
314         public static final String XML_TAG_BSSID = "BSSID";
315         public static final String XML_TAG_CONFIG_KEY = "ConfigKey";
316         public static final String XML_TAG_PRE_SHARED_KEY = "PreSharedKey";
317         public static final String XML_TAG_WEP_KEYS = "WEPKeys";
318         public static final String XML_TAG_WEP_TX_KEY_INDEX = "WEPTxKeyIndex";
319         public static final String XML_TAG_HIDDEN_SSID = "HiddenSSID";
320         public static final String XML_TAG_REQUIRE_PMF = "RequirePMF";
321         public static final String XML_TAG_ALLOWED_KEY_MGMT = "AllowedKeyMgmt";
322         public static final String XML_TAG_ALLOWED_PROTOCOLS = "AllowedProtocols";
323         public static final String XML_TAG_ALLOWED_AUTH_ALGOS = "AllowedAuthAlgos";
324         public static final String XML_TAG_ALLOWED_GROUP_CIPHERS = "AllowedGroupCiphers";
325         public static final String XML_TAG_ALLOWED_PAIRWISE_CIPHERS = "AllowedPairwiseCiphers";
326         public static final String XML_TAG_SHARED = "Shared";
327         public static final String XML_TAG_STATUS = "Status";
328         public static final String XML_TAG_FQDN = "FQDN";
329         public static final String XML_TAG_PROVIDER_FRIENDLY_NAME = "ProviderFriendlyName";
330         public static final String XML_TAG_LINKED_NETWORKS_LIST = "LinkedNetworksList";
331         public static final String XML_TAG_DEFAULT_GW_MAC_ADDRESS = "DefaultGwMacAddress";
332         public static final String XML_TAG_VALIDATED_INTERNET_ACCESS = "ValidatedInternetAccess";
333         public static final String XML_TAG_NO_INTERNET_ACCESS_EXPECTED = "NoInternetAccessExpected";
334         public static final String XML_TAG_USER_APPROVED = "UserApproved";
335         public static final String XML_TAG_METERED_HINT = "MeteredHint";
336         public static final String XML_TAG_METERED_OVERRIDE = "MeteredOverride";
337         public static final String XML_TAG_USE_EXTERNAL_SCORES = "UseExternalScores";
338         public static final String XML_TAG_NUM_ASSOCIATION = "NumAssociation";
339         public static final String XML_TAG_CREATOR_UID = "CreatorUid";
340         public static final String XML_TAG_CREATOR_NAME = "CreatorName";
341         public static final String XML_TAG_CREATION_TIME = "CreationTime";
342         public static final String XML_TAG_LAST_UPDATE_UID = "LastUpdateUid";
343         public static final String XML_TAG_LAST_UPDATE_NAME = "LastUpdateName";
344         public static final String XML_TAG_LAST_CONNECT_UID = "LastConnectUid";
345         public static final String XML_TAG_IS_LEGACY_PASSPOINT_CONFIG = "IsLegacyPasspointConfig";
346         public static final String XML_TAG_ROAMING_CONSORTIUM_OIS = "RoamingConsortiumOIs";
347         public static final String XML_TAG_RANDOMIZED_MAC_ADDRESS = "RandomizedMacAddress";
348 
349         /**
350          * Write WepKeys to the XML stream.
351          * WepKeys array is intialized in WifiConfiguration constructor, but all of the elements
352          * are set to null. User may chose to set any one of the key elements in WifiConfiguration.
353          * XmlUtils serialization doesn't handle this array of nulls well .
354          * So, write empty strings if some of the keys are not initialized and null if all of
355          * the elements are empty.
356          */
writeWepKeysToXml(XmlSerializer out, String[] wepKeys)357         private static void writeWepKeysToXml(XmlSerializer out, String[] wepKeys)
358                 throws XmlPullParserException, IOException {
359             String[] wepKeysToWrite = new String[wepKeys.length];
360             boolean hasWepKey = false;
361             for (int i = 0; i < wepKeys.length; i++) {
362                 if (wepKeys[i] == null) {
363                     wepKeysToWrite[i] = new String();
364                 } else {
365                     wepKeysToWrite[i] = wepKeys[i];
366                     hasWepKey = true;
367                 }
368             }
369             if (hasWepKey) {
370                 XmlUtil.writeNextValue(out, XML_TAG_WEP_KEYS, wepKeysToWrite);
371             } else {
372                 XmlUtil.writeNextValue(out, XML_TAG_WEP_KEYS, null);
373             }
374         }
375 
376         /**
377          * Write the Configuration data elements that are common for backup & config store to the
378          * XML stream.
379          *
380          * @param out           XmlSerializer instance pointing to the XML stream.
381          * @param configuration WifiConfiguration object to be serialized.
382          */
writeCommonElementsToXml( XmlSerializer out, WifiConfiguration configuration)383         public static void writeCommonElementsToXml(
384                 XmlSerializer out, WifiConfiguration configuration)
385                 throws XmlPullParserException, IOException {
386             XmlUtil.writeNextValue(out, XML_TAG_CONFIG_KEY, configuration.configKey());
387             XmlUtil.writeNextValue(out, XML_TAG_SSID, configuration.SSID);
388             XmlUtil.writeNextValue(out, XML_TAG_BSSID, configuration.BSSID);
389             XmlUtil.writeNextValue(out, XML_TAG_PRE_SHARED_KEY, configuration.preSharedKey);
390             writeWepKeysToXml(out, configuration.wepKeys);
391             XmlUtil.writeNextValue(out, XML_TAG_WEP_TX_KEY_INDEX, configuration.wepTxKeyIndex);
392             XmlUtil.writeNextValue(out, XML_TAG_HIDDEN_SSID, configuration.hiddenSSID);
393             XmlUtil.writeNextValue(out, XML_TAG_REQUIRE_PMF, configuration.requirePMF);
394             XmlUtil.writeNextValue(
395                     out, XML_TAG_ALLOWED_KEY_MGMT,
396                     configuration.allowedKeyManagement.toByteArray());
397             XmlUtil.writeNextValue(
398                     out, XML_TAG_ALLOWED_PROTOCOLS,
399                     configuration.allowedProtocols.toByteArray());
400             XmlUtil.writeNextValue(
401                     out, XML_TAG_ALLOWED_AUTH_ALGOS,
402                     configuration.allowedAuthAlgorithms.toByteArray());
403             XmlUtil.writeNextValue(
404                     out, XML_TAG_ALLOWED_GROUP_CIPHERS,
405                     configuration.allowedGroupCiphers.toByteArray());
406             XmlUtil.writeNextValue(
407                     out, XML_TAG_ALLOWED_PAIRWISE_CIPHERS,
408                     configuration.allowedPairwiseCiphers.toByteArray());
409             XmlUtil.writeNextValue(out, XML_TAG_SHARED, configuration.shared);
410         }
411 
412         /**
413          * Write the Configuration data elements for backup from the provided Configuration to the
414          * XML stream.
415          * Note: This is a subset of the elements serialized for config store.
416          *
417          * @param out           XmlSerializer instance pointing to the XML stream.
418          * @param configuration WifiConfiguration object to be serialized.
419          */
writeToXmlForBackup(XmlSerializer out, WifiConfiguration configuration)420         public static void writeToXmlForBackup(XmlSerializer out, WifiConfiguration configuration)
421                 throws XmlPullParserException, IOException {
422             writeCommonElementsToXml(out, configuration);
423         }
424 
425         /**
426          * Write the Configuration data elements for config store from the provided Configuration
427          * to the XML stream.
428          *
429          * @param out           XmlSerializer instance pointing to the XML stream.
430          * @param configuration WifiConfiguration object to be serialized.
431          */
writeToXmlForConfigStore( XmlSerializer out, WifiConfiguration configuration)432         public static void writeToXmlForConfigStore(
433                 XmlSerializer out, WifiConfiguration configuration)
434                 throws XmlPullParserException, IOException {
435             writeCommonElementsToXml(out, configuration);
436             XmlUtil.writeNextValue(out, XML_TAG_STATUS, configuration.status);
437             XmlUtil.writeNextValue(out, XML_TAG_FQDN, configuration.FQDN);
438             XmlUtil.writeNextValue(
439                     out, XML_TAG_PROVIDER_FRIENDLY_NAME, configuration.providerFriendlyName);
440             XmlUtil.writeNextValue(
441                     out, XML_TAG_LINKED_NETWORKS_LIST, configuration.linkedConfigurations);
442             XmlUtil.writeNextValue(
443                     out, XML_TAG_DEFAULT_GW_MAC_ADDRESS, configuration.defaultGwMacAddress);
444             XmlUtil.writeNextValue(
445                     out, XML_TAG_VALIDATED_INTERNET_ACCESS, configuration.validatedInternetAccess);
446             XmlUtil.writeNextValue(
447                     out, XML_TAG_NO_INTERNET_ACCESS_EXPECTED,
448                     configuration.noInternetAccessExpected);
449             XmlUtil.writeNextValue(out, XML_TAG_USER_APPROVED, configuration.userApproved);
450             XmlUtil.writeNextValue(out, XML_TAG_METERED_HINT, configuration.meteredHint);
451             XmlUtil.writeNextValue(out, XML_TAG_METERED_OVERRIDE, configuration.meteredOverride);
452             XmlUtil.writeNextValue(
453                     out, XML_TAG_USE_EXTERNAL_SCORES, configuration.useExternalScores);
454             XmlUtil.writeNextValue(out, XML_TAG_NUM_ASSOCIATION, configuration.numAssociation);
455             XmlUtil.writeNextValue(out, XML_TAG_CREATOR_UID, configuration.creatorUid);
456             XmlUtil.writeNextValue(out, XML_TAG_CREATOR_NAME, configuration.creatorName);
457             XmlUtil.writeNextValue(out, XML_TAG_CREATION_TIME, configuration.creationTime);
458             XmlUtil.writeNextValue(out, XML_TAG_LAST_UPDATE_UID, configuration.lastUpdateUid);
459             XmlUtil.writeNextValue(out, XML_TAG_LAST_UPDATE_NAME, configuration.lastUpdateName);
460             XmlUtil.writeNextValue(out, XML_TAG_LAST_CONNECT_UID, configuration.lastConnectUid);
461             XmlUtil.writeNextValue(
462                     out, XML_TAG_IS_LEGACY_PASSPOINT_CONFIG,
463                     configuration.isLegacyPasspointConfig);
464             XmlUtil.writeNextValue(
465                     out, XML_TAG_ROAMING_CONSORTIUM_OIS, configuration.roamingConsortiumIds);
466             XmlUtil.writeNextValue(out, XML_TAG_RANDOMIZED_MAC_ADDRESS,
467                     configuration.getRandomizedMacAddress().toString());
468         }
469 
470         /**
471          * Populate wepKeys array elements only if they were non-empty in the backup data.
472          *
473          * @throws XmlPullParserException if parsing errors occur.
474          */
populateWepKeysFromXmlValue(Object value, String[] wepKeys)475         private static void populateWepKeysFromXmlValue(Object value, String[] wepKeys)
476                 throws XmlPullParserException, IOException {
477             String[] wepKeysInData = (String[]) value;
478             if (wepKeysInData == null) {
479                 return;
480             }
481             if (wepKeysInData.length != wepKeys.length) {
482                 throw new XmlPullParserException(
483                         "Invalid Wep Keys length: " + wepKeysInData.length);
484             }
485             for (int i = 0; i < wepKeys.length; i++) {
486                 if (wepKeysInData[i].isEmpty()) {
487                     wepKeys[i] = null;
488                 } else {
489                     wepKeys[i] = wepKeysInData[i];
490                 }
491             }
492         }
493 
494         /**
495          * Parses the configuration data elements from the provided XML stream to a
496          * WifiConfiguration object.
497          * Note: This is used for parsing both backup data and config store data. Looping through
498          * the tags make it easy to add or remove elements in the future versions if needed.
499          *
500          * @param in            XmlPullParser instance pointing to the XML stream.
501          * @param outerTagDepth depth of the outer tag in the XML document.
502          * @return Pair<Config key, WifiConfiguration object> if parsing is successful,
503          * null otherwise.
504          */
parseFromXml( XmlPullParser in, int outerTagDepth)505         public static Pair<String, WifiConfiguration> parseFromXml(
506                 XmlPullParser in, int outerTagDepth)
507                 throws XmlPullParserException, IOException {
508             WifiConfiguration configuration = new WifiConfiguration();
509             String configKeyInData = null;
510 
511             // Loop through and parse out all the elements from the stream within this section.
512             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
513                 String[] valueName = new String[1];
514                 Object value = XmlUtil.readCurrentValue(in, valueName);
515                 if (valueName[0] == null) {
516                     throw new XmlPullParserException("Missing value name");
517                 }
518                 switch (valueName[0]) {
519                     case XML_TAG_CONFIG_KEY:
520                         configKeyInData = (String) value;
521                         break;
522                     case XML_TAG_SSID:
523                         configuration.SSID = (String) value;
524                         break;
525                     case XML_TAG_BSSID:
526                         configuration.BSSID = (String) value;
527                         break;
528                     case XML_TAG_PRE_SHARED_KEY:
529                         configuration.preSharedKey = (String) value;
530                         break;
531                     case XML_TAG_WEP_KEYS:
532                         populateWepKeysFromXmlValue(value, configuration.wepKeys);
533                         break;
534                     case XML_TAG_WEP_TX_KEY_INDEX:
535                         configuration.wepTxKeyIndex = (int) value;
536                         break;
537                     case XML_TAG_HIDDEN_SSID:
538                         configuration.hiddenSSID = (boolean) value;
539                         break;
540                     case XML_TAG_REQUIRE_PMF:
541                         configuration.requirePMF = (boolean) value;
542                         break;
543                     case XML_TAG_ALLOWED_KEY_MGMT:
544                         byte[] allowedKeyMgmt = (byte[]) value;
545                         configuration.allowedKeyManagement = BitSet.valueOf(allowedKeyMgmt);
546                         break;
547                     case XML_TAG_ALLOWED_PROTOCOLS:
548                         byte[] allowedProtocols = (byte[]) value;
549                         configuration.allowedProtocols = BitSet.valueOf(allowedProtocols);
550                         break;
551                     case XML_TAG_ALLOWED_AUTH_ALGOS:
552                         byte[] allowedAuthAlgorithms = (byte[]) value;
553                         configuration.allowedAuthAlgorithms = BitSet.valueOf(allowedAuthAlgorithms);
554                         break;
555                     case XML_TAG_ALLOWED_GROUP_CIPHERS:
556                         byte[] allowedGroupCiphers = (byte[]) value;
557                         configuration.allowedGroupCiphers = BitSet.valueOf(allowedGroupCiphers);
558                         break;
559                     case XML_TAG_ALLOWED_PAIRWISE_CIPHERS:
560                         byte[] allowedPairwiseCiphers = (byte[]) value;
561                         configuration.allowedPairwiseCiphers =
562                                 BitSet.valueOf(allowedPairwiseCiphers);
563                         break;
564                     case XML_TAG_SHARED:
565                         configuration.shared = (boolean) value;
566                         break;
567                     case XML_TAG_STATUS:
568                         int status = (int) value;
569                         // Any network which was CURRENT before reboot needs
570                         // to be restored to ENABLED.
571                         if (status == WifiConfiguration.Status.CURRENT) {
572                             status = WifiConfiguration.Status.ENABLED;
573                         }
574                         configuration.status = status;
575                         break;
576                     case XML_TAG_FQDN:
577                         configuration.FQDN = (String) value;
578                         break;
579                     case XML_TAG_PROVIDER_FRIENDLY_NAME:
580                         configuration.providerFriendlyName = (String) value;
581                         break;
582                     case XML_TAG_LINKED_NETWORKS_LIST:
583                         configuration.linkedConfigurations = (HashMap<String, Integer>) value;
584                         break;
585                     case XML_TAG_DEFAULT_GW_MAC_ADDRESS:
586                         configuration.defaultGwMacAddress = (String) value;
587                         break;
588                     case XML_TAG_VALIDATED_INTERNET_ACCESS:
589                         configuration.validatedInternetAccess = (boolean) value;
590                         break;
591                     case XML_TAG_NO_INTERNET_ACCESS_EXPECTED:
592                         configuration.noInternetAccessExpected = (boolean) value;
593                         break;
594                     case XML_TAG_USER_APPROVED:
595                         configuration.userApproved = (int) value;
596                         break;
597                     case XML_TAG_METERED_HINT:
598                         configuration.meteredHint = (boolean) value;
599                         break;
600                     case XML_TAG_METERED_OVERRIDE:
601                         configuration.meteredOverride = (int) value;
602                         break;
603                     case XML_TAG_USE_EXTERNAL_SCORES:
604                         configuration.useExternalScores = (boolean) value;
605                         break;
606                     case XML_TAG_NUM_ASSOCIATION:
607                         configuration.numAssociation = (int) value;
608                         break;
609                     case XML_TAG_CREATOR_UID:
610                         configuration.creatorUid = (int) value;
611                         break;
612                     case XML_TAG_CREATOR_NAME:
613                         configuration.creatorName = (String) value;
614                         break;
615                     case XML_TAG_CREATION_TIME:
616                         configuration.creationTime = (String) value;
617                         break;
618                     case XML_TAG_LAST_UPDATE_UID:
619                         configuration.lastUpdateUid = (int) value;
620                         break;
621                     case XML_TAG_LAST_UPDATE_NAME:
622                         configuration.lastUpdateName = (String) value;
623                         break;
624                     case XML_TAG_LAST_CONNECT_UID:
625                         configuration.lastConnectUid = (int) value;
626                         break;
627                     case XML_TAG_IS_LEGACY_PASSPOINT_CONFIG:
628                         configuration.isLegacyPasspointConfig = (boolean) value;
629                         break;
630                     case XML_TAG_ROAMING_CONSORTIUM_OIS:
631                         configuration.roamingConsortiumIds = (long[]) value;
632                         break;
633                     case XML_TAG_RANDOMIZED_MAC_ADDRESS:
634                         configuration.setRandomizedMacAddress(
635                                 MacAddress.fromString((String) value));
636                         break;
637                     default:
638                         throw new XmlPullParserException(
639                                 "Unknown value name found: " + valueName[0]);
640                 }
641             }
642             return Pair.create(configKeyInData, configuration);
643         }
644     }
645 
646     /**
647      * Utility class to serialize and deseriaize {@link IpConfiguration} object to XML & vice versa.
648      * This is used by both {@link com.android.server.wifi.WifiConfigStore} &
649      * {@link com.android.server.wifi.WifiBackupRestore} modules.
650      */
651     public static class IpConfigurationXmlUtil {
652 
653         /**
654          * List of XML tags corresponding to IpConfiguration object elements.
655          */
656         public static final String XML_TAG_IP_ASSIGNMENT = "IpAssignment";
657         public static final String XML_TAG_LINK_ADDRESS = "LinkAddress";
658         public static final String XML_TAG_LINK_PREFIX_LENGTH = "LinkPrefixLength";
659         public static final String XML_TAG_GATEWAY_ADDRESS = "GatewayAddress";
660         public static final String XML_TAG_DNS_SERVER_ADDRESSES = "DNSServers";
661         public static final String XML_TAG_PROXY_SETTINGS = "ProxySettings";
662         public static final String XML_TAG_PROXY_HOST = "ProxyHost";
663         public static final String XML_TAG_PROXY_PORT = "ProxyPort";
664         public static final String XML_TAG_PROXY_PAC_FILE = "ProxyPac";
665         public static final String XML_TAG_PROXY_EXCLUSION_LIST = "ProxyExclusionList";
666 
667         /**
668          * Write the static IP configuration data elements to XML stream.
669          */
writeStaticIpConfigurationToXml( XmlSerializer out, StaticIpConfiguration staticIpConfiguration)670         private static void writeStaticIpConfigurationToXml(
671                 XmlSerializer out, StaticIpConfiguration staticIpConfiguration)
672                 throws XmlPullParserException, IOException {
673             if (staticIpConfiguration.ipAddress != null) {
674                 XmlUtil.writeNextValue(
675                         out, XML_TAG_LINK_ADDRESS,
676                         staticIpConfiguration.ipAddress.getAddress().getHostAddress());
677                 XmlUtil.writeNextValue(
678                         out, XML_TAG_LINK_PREFIX_LENGTH,
679                         staticIpConfiguration.ipAddress.getPrefixLength());
680             } else {
681                 XmlUtil.writeNextValue(
682                         out, XML_TAG_LINK_ADDRESS, null);
683                 XmlUtil.writeNextValue(
684                         out, XML_TAG_LINK_PREFIX_LENGTH, null);
685             }
686             if (staticIpConfiguration.gateway != null) {
687                 XmlUtil.writeNextValue(
688                         out, XML_TAG_GATEWAY_ADDRESS,
689                         staticIpConfiguration.gateway.getHostAddress());
690             } else {
691                 XmlUtil.writeNextValue(
692                         out, XML_TAG_GATEWAY_ADDRESS, null);
693 
694             }
695             if (staticIpConfiguration.dnsServers != null) {
696                 // Create a string array of DNS server addresses
697                 String[] dnsServers = new String[staticIpConfiguration.dnsServers.size()];
698                 int dnsServerIdx = 0;
699                 for (InetAddress inetAddr : staticIpConfiguration.dnsServers) {
700                     dnsServers[dnsServerIdx++] = inetAddr.getHostAddress();
701                 }
702                 XmlUtil.writeNextValue(
703                         out, XML_TAG_DNS_SERVER_ADDRESSES, dnsServers);
704             } else {
705                 XmlUtil.writeNextValue(
706                         out, XML_TAG_DNS_SERVER_ADDRESSES, null);
707             }
708         }
709 
710         /**
711          * Write the IP configuration data elements from the provided Configuration to the XML
712          * stream.
713          *
714          * @param out             XmlSerializer instance pointing to the XML stream.
715          * @param ipConfiguration IpConfiguration object to be serialized.
716          */
writeToXml(XmlSerializer out, IpConfiguration ipConfiguration)717         public static void writeToXml(XmlSerializer out, IpConfiguration ipConfiguration)
718                 throws XmlPullParserException, IOException {
719             // Write IP assignment settings
720             XmlUtil.writeNextValue(out, XML_TAG_IP_ASSIGNMENT,
721                     ipConfiguration.ipAssignment.toString());
722             switch (ipConfiguration.ipAssignment) {
723                 case STATIC:
724                     writeStaticIpConfigurationToXml(
725                             out, ipConfiguration.getStaticIpConfiguration());
726                     break;
727                 default:
728                     break;
729             }
730 
731             // Write proxy settings
732             XmlUtil.writeNextValue(
733                     out, XML_TAG_PROXY_SETTINGS,
734                     ipConfiguration.proxySettings.toString());
735             switch (ipConfiguration.proxySettings) {
736                 case STATIC:
737                     XmlUtil.writeNextValue(
738                             out, XML_TAG_PROXY_HOST,
739                             ipConfiguration.httpProxy.getHost());
740                     XmlUtil.writeNextValue(
741                             out, XML_TAG_PROXY_PORT,
742                             ipConfiguration.httpProxy.getPort());
743                     XmlUtil.writeNextValue(
744                             out, XML_TAG_PROXY_EXCLUSION_LIST,
745                             ipConfiguration.httpProxy.getExclusionListAsString());
746                     break;
747                 case PAC:
748                     XmlUtil.writeNextValue(
749                             out, XML_TAG_PROXY_PAC_FILE,
750                             ipConfiguration.httpProxy.getPacFileUrl().toString());
751                     break;
752                 default:
753                     break;
754             }
755         }
756 
757         /**
758          * Parse out the static IP configuration from the XML stream.
759          */
parseStaticIpConfigurationFromXml(XmlPullParser in)760         private static StaticIpConfiguration parseStaticIpConfigurationFromXml(XmlPullParser in)
761                 throws XmlPullParserException, IOException {
762             StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();
763 
764             String linkAddressString =
765                     (String) XmlUtil.readNextValueWithName(in, XML_TAG_LINK_ADDRESS);
766             Integer linkPrefixLength =
767                     (Integer) XmlUtil.readNextValueWithName(in, XML_TAG_LINK_PREFIX_LENGTH);
768             if (linkAddressString != null && linkPrefixLength != null) {
769                 LinkAddress linkAddress = new LinkAddress(
770                         NetworkUtils.numericToInetAddress(linkAddressString),
771                         linkPrefixLength);
772                 if (linkAddress.getAddress() instanceof Inet4Address) {
773                     staticIpConfiguration.ipAddress = linkAddress;
774                 } else {
775                     Log.w(TAG, "Non-IPv4 address: " + linkAddress);
776                 }
777             }
778             String gatewayAddressString =
779                     (String) XmlUtil.readNextValueWithName(in, XML_TAG_GATEWAY_ADDRESS);
780             if (gatewayAddressString != null) {
781                 LinkAddress dest = null;
782                 InetAddress gateway =
783                         NetworkUtils.numericToInetAddress(gatewayAddressString);
784                 RouteInfo route = new RouteInfo(dest, gateway);
785                 if (route.isIPv4Default()) {
786                     staticIpConfiguration.gateway = gateway;
787                 } else {
788                     Log.w(TAG, "Non-IPv4 default route: " + route);
789                 }
790             }
791             String[] dnsServerAddressesString =
792                     (String[]) XmlUtil.readNextValueWithName(in, XML_TAG_DNS_SERVER_ADDRESSES);
793             if (dnsServerAddressesString != null) {
794                 for (String dnsServerAddressString : dnsServerAddressesString) {
795                     InetAddress dnsServerAddress =
796                             NetworkUtils.numericToInetAddress(dnsServerAddressString);
797                     staticIpConfiguration.dnsServers.add(dnsServerAddress);
798                 }
799             }
800             return staticIpConfiguration;
801         }
802 
803         /**
804          * Parses the IP configuration data elements from the provided XML stream to an
805          * IpConfiguration object.
806          *
807          * @param in            XmlPullParser instance pointing to the XML stream.
808          * @param outerTagDepth depth of the outer tag in the XML document.
809          * @return IpConfiguration object if parsing is successful, null otherwise.
810          */
parseFromXml(XmlPullParser in, int outerTagDepth)811         public static IpConfiguration parseFromXml(XmlPullParser in, int outerTagDepth)
812                 throws XmlPullParserException, IOException {
813             IpConfiguration ipConfiguration = new IpConfiguration();
814 
815             // Parse out the IP assignment info first.
816             String ipAssignmentString =
817                     (String) XmlUtil.readNextValueWithName(in, XML_TAG_IP_ASSIGNMENT);
818             IpAssignment ipAssignment = IpAssignment.valueOf(ipAssignmentString);
819             ipConfiguration.setIpAssignment(ipAssignment);
820             switch (ipAssignment) {
821                 case STATIC:
822                     ipConfiguration.setStaticIpConfiguration(parseStaticIpConfigurationFromXml(in));
823                     break;
824                 case DHCP:
825                 case UNASSIGNED:
826                     break;
827                 default:
828                     throw new XmlPullParserException("Unknown ip assignment type: " + ipAssignment);
829             }
830 
831             // Parse out the proxy settings next.
832             String proxySettingsString =
833                     (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_SETTINGS);
834             ProxySettings proxySettings = ProxySettings.valueOf(proxySettingsString);
835             ipConfiguration.setProxySettings(proxySettings);
836             switch (proxySettings) {
837                 case STATIC:
838                     String proxyHost =
839                             (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_HOST);
840                     int proxyPort =
841                             (int) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_PORT);
842                     String proxyExclusionList =
843                             (String) XmlUtil.readNextValueWithName(
844                                     in, XML_TAG_PROXY_EXCLUSION_LIST);
845                     ipConfiguration.setHttpProxy(
846                             new ProxyInfo(proxyHost, proxyPort, proxyExclusionList));
847                     break;
848                 case PAC:
849                     String proxyPacFile =
850                             (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_PAC_FILE);
851                     ipConfiguration.setHttpProxy(new ProxyInfo(proxyPacFile));
852                     break;
853                 case NONE:
854                 case UNASSIGNED:
855                     break;
856                 default:
857                     throw new XmlPullParserException(
858                             "Unknown proxy settings type: " + proxySettings);
859             }
860             return ipConfiguration;
861         }
862     }
863 
864     /**
865      * Utility class to serialize and deseriaize {@link NetworkSelectionStatus} object to XML &
866      * vice versa. This is used by {@link com.android.server.wifi.WifiConfigStore} module.
867      */
868     public static class NetworkSelectionStatusXmlUtil {
869 
870         /**
871          * List of XML tags corresponding to NetworkSelectionStatus object elements.
872          */
873         public static final String XML_TAG_SELECTION_STATUS = "SelectionStatus";
874         public static final String XML_TAG_DISABLE_REASON = "DisableReason";
875         public static final String XML_TAG_CONNECT_CHOICE = "ConnectChoice";
876         public static final String XML_TAG_CONNECT_CHOICE_TIMESTAMP = "ConnectChoiceTimeStamp";
877         public static final String XML_TAG_HAS_EVER_CONNECTED = "HasEverConnected";
878 
879         /**
880          * Write the NetworkSelectionStatus data elements from the provided status to the XML
881          * stream.
882          *
883          * @param out             XmlSerializer instance pointing to the XML stream.
884          * @param selectionStatus NetworkSelectionStatus object to be serialized.
885          */
writeToXml(XmlSerializer out, NetworkSelectionStatus selectionStatus)886         public static void writeToXml(XmlSerializer out, NetworkSelectionStatus selectionStatus)
887                 throws XmlPullParserException, IOException {
888             XmlUtil.writeNextValue(
889                     out, XML_TAG_SELECTION_STATUS, selectionStatus.getNetworkStatusString());
890             XmlUtil.writeNextValue(
891                     out, XML_TAG_DISABLE_REASON, selectionStatus.getNetworkDisableReasonString());
892             XmlUtil.writeNextValue(out, XML_TAG_CONNECT_CHOICE, selectionStatus.getConnectChoice());
893             XmlUtil.writeNextValue(
894                     out, XML_TAG_CONNECT_CHOICE_TIMESTAMP,
895                     selectionStatus.getConnectChoiceTimestamp());
896             XmlUtil.writeNextValue(
897                     out, XML_TAG_HAS_EVER_CONNECTED, selectionStatus.getHasEverConnected());
898         }
899 
900         /**
901          * Parses the NetworkSelectionStatus data elements from the provided XML stream to a
902          * NetworkSelectionStatus object.
903          *
904          * @param in            XmlPullParser instance pointing to the XML stream.
905          * @param outerTagDepth depth of the outer tag in the XML document.
906          * @return NetworkSelectionStatus object if parsing is successful, null otherwise.
907          */
parseFromXml(XmlPullParser in, int outerTagDepth)908         public static NetworkSelectionStatus parseFromXml(XmlPullParser in, int outerTagDepth)
909                 throws XmlPullParserException, IOException {
910             NetworkSelectionStatus selectionStatus = new NetworkSelectionStatus();
911             String statusString = "";
912             String disableReasonString = "";
913 
914             // Loop through and parse out all the elements from the stream within this section.
915             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
916                 String[] valueName = new String[1];
917                 Object value = XmlUtil.readCurrentValue(in, valueName);
918                 if (valueName[0] == null) {
919                     throw new XmlPullParserException("Missing value name");
920                 }
921                 switch (valueName[0]) {
922                     case XML_TAG_SELECTION_STATUS:
923                         statusString = (String) value;
924                         break;
925                     case XML_TAG_DISABLE_REASON:
926                         disableReasonString = (String) value;
927                         break;
928                     case XML_TAG_CONNECT_CHOICE:
929                         selectionStatus.setConnectChoice((String) value);
930                         break;
931                     case XML_TAG_CONNECT_CHOICE_TIMESTAMP:
932                         selectionStatus.setConnectChoiceTimestamp((long) value);
933                         break;
934                     case XML_TAG_HAS_EVER_CONNECTED:
935                         selectionStatus.setHasEverConnected((boolean) value);
936                         break;
937                     default:
938                         throw new XmlPullParserException(
939                                 "Unknown value name found: " + valueName[0]);
940                 }
941             }
942             // Now figure out the network selection status codes from |selectionStatusString| &
943             // |disableReasonString|.
944             int status =
945                     Arrays.asList(NetworkSelectionStatus.QUALITY_NETWORK_SELECTION_STATUS)
946                             .indexOf(statusString);
947             int disableReason =
948                     Arrays.asList(NetworkSelectionStatus.QUALITY_NETWORK_SELECTION_DISABLE_REASON)
949                             .indexOf(disableReasonString);
950 
951             // If either of the above codes are invalid or if the network was temporarily disabled
952             // (blacklisted), restore the status as enabled. We don't want to persist blacklists
953             // across reboots.
954             if (status == -1 || disableReason == -1 ||
955                     status == NetworkSelectionStatus.NETWORK_SELECTION_TEMPORARY_DISABLED) {
956                 status = NetworkSelectionStatus.NETWORK_SELECTION_ENABLED;
957                 disableReason = NetworkSelectionStatus.NETWORK_SELECTION_ENABLE;
958             }
959             selectionStatus.setNetworkSelectionStatus(status);
960             selectionStatus.setNetworkSelectionDisableReason(disableReason);
961             return selectionStatus;
962         }
963     }
964 
965     /**
966      * Utility class to serialize and deseriaize {@link WifiEnterpriseConfig} object to XML &
967      * vice versa. This is used by {@link com.android.server.wifi.WifiConfigStore} module.
968      */
969     public static class WifiEnterpriseConfigXmlUtil {
970 
971         /**
972          * List of XML tags corresponding to WifiEnterpriseConfig object elements.
973          */
974         public static final String XML_TAG_IDENTITY = "Identity";
975         public static final String XML_TAG_ANON_IDENTITY = "AnonIdentity";
976         public static final String XML_TAG_PASSWORD = "Password";
977         public static final String XML_TAG_CLIENT_CERT = "ClientCert";
978         public static final String XML_TAG_CA_CERT = "CaCert";
979         public static final String XML_TAG_SUBJECT_MATCH = "SubjectMatch";
980         public static final String XML_TAG_ENGINE = "Engine";
981         public static final String XML_TAG_ENGINE_ID = "EngineId";
982         public static final String XML_TAG_PRIVATE_KEY_ID = "PrivateKeyId";
983         public static final String XML_TAG_ALT_SUBJECT_MATCH = "AltSubjectMatch";
984         public static final String XML_TAG_DOM_SUFFIX_MATCH = "DomSuffixMatch";
985         public static final String XML_TAG_CA_PATH = "CaPath";
986         public static final String XML_TAG_EAP_METHOD = "EapMethod";
987         public static final String XML_TAG_PHASE2_METHOD = "Phase2Method";
988         public static final String XML_TAG_PLMN = "PLMN";
989         public static final String XML_TAG_REALM = "Realm";
990 
991         /**
992          * Write the WifiEnterpriseConfig data elements from the provided config to the XML
993          * stream.
994          *
995          * @param out              XmlSerializer instance pointing to the XML stream.
996          * @param enterpriseConfig WifiEnterpriseConfig object to be serialized.
997          */
writeToXml(XmlSerializer out, WifiEnterpriseConfig enterpriseConfig)998         public static void writeToXml(XmlSerializer out, WifiEnterpriseConfig enterpriseConfig)
999                 throws XmlPullParserException, IOException {
1000             XmlUtil.writeNextValue(out, XML_TAG_IDENTITY,
1001                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.IDENTITY_KEY));
1002             XmlUtil.writeNextValue(out, XML_TAG_ANON_IDENTITY,
1003                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ANON_IDENTITY_KEY));
1004             XmlUtil.writeNextValue(out, XML_TAG_PASSWORD,
1005                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.PASSWORD_KEY));
1006             XmlUtil.writeNextValue(out, XML_TAG_CLIENT_CERT,
1007                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.CLIENT_CERT_KEY));
1008             XmlUtil.writeNextValue(out, XML_TAG_CA_CERT,
1009                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.CA_CERT_KEY));
1010             XmlUtil.writeNextValue(out, XML_TAG_SUBJECT_MATCH,
1011                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.SUBJECT_MATCH_KEY));
1012             XmlUtil.writeNextValue(out, XML_TAG_ENGINE,
1013                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ENGINE_KEY));
1014             XmlUtil.writeNextValue(out, XML_TAG_ENGINE_ID,
1015                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY));
1016             XmlUtil.writeNextValue(out, XML_TAG_PRIVATE_KEY_ID,
1017                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY));
1018             XmlUtil.writeNextValue(out, XML_TAG_ALT_SUBJECT_MATCH,
1019                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY));
1020             XmlUtil.writeNextValue(out, XML_TAG_DOM_SUFFIX_MATCH,
1021                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY));
1022             XmlUtil.writeNextValue(out, XML_TAG_CA_PATH,
1023                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.CA_PATH_KEY));
1024             XmlUtil.writeNextValue(out, XML_TAG_EAP_METHOD, enterpriseConfig.getEapMethod());
1025             XmlUtil.writeNextValue(out, XML_TAG_PHASE2_METHOD, enterpriseConfig.getPhase2Method());
1026             XmlUtil.writeNextValue(out, XML_TAG_PLMN, enterpriseConfig.getPlmn());
1027             XmlUtil.writeNextValue(out, XML_TAG_REALM, enterpriseConfig.getRealm());
1028         }
1029 
1030         /**
1031          * Parses the data elements from the provided XML stream to a WifiEnterpriseConfig object.
1032          *
1033          * @param in            XmlPullParser instance pointing to the XML stream.
1034          * @param outerTagDepth depth of the outer tag in the XML document.
1035          * @return WifiEnterpriseConfig object if parsing is successful, null otherwise.
1036          */
parseFromXml(XmlPullParser in, int outerTagDepth)1037         public static WifiEnterpriseConfig parseFromXml(XmlPullParser in, int outerTagDepth)
1038                 throws XmlPullParserException, IOException {
1039             WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
1040 
1041             // Loop through and parse out all the elements from the stream within this section.
1042             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
1043                 String[] valueName = new String[1];
1044                 Object value = XmlUtil.readCurrentValue(in, valueName);
1045                 if (valueName[0] == null) {
1046                     throw new XmlPullParserException("Missing value name");
1047                 }
1048                 switch (valueName[0]) {
1049                     case XML_TAG_IDENTITY:
1050                         enterpriseConfig.setFieldValue(
1051                                 WifiEnterpriseConfig.IDENTITY_KEY, (String) value);
1052                         break;
1053                     case XML_TAG_ANON_IDENTITY:
1054                         enterpriseConfig.setFieldValue(
1055                                 WifiEnterpriseConfig.ANON_IDENTITY_KEY, (String) value);
1056                         break;
1057                     case XML_TAG_PASSWORD:
1058                         enterpriseConfig.setFieldValue(
1059                                 WifiEnterpriseConfig.PASSWORD_KEY, (String) value);
1060                         break;
1061                     case XML_TAG_CLIENT_CERT:
1062                         enterpriseConfig.setFieldValue(
1063                                 WifiEnterpriseConfig.CLIENT_CERT_KEY, (String) value);
1064                         break;
1065                     case XML_TAG_CA_CERT:
1066                         enterpriseConfig.setFieldValue(
1067                                 WifiEnterpriseConfig.CA_CERT_KEY, (String) value);
1068                         break;
1069                     case XML_TAG_SUBJECT_MATCH:
1070                         enterpriseConfig.setFieldValue(
1071                                 WifiEnterpriseConfig.SUBJECT_MATCH_KEY, (String) value);
1072                         break;
1073                     case XML_TAG_ENGINE:
1074                         enterpriseConfig.setFieldValue(
1075                                 WifiEnterpriseConfig.ENGINE_KEY, (String) value);
1076                         break;
1077                     case XML_TAG_ENGINE_ID:
1078                         enterpriseConfig.setFieldValue(
1079                                 WifiEnterpriseConfig.ENGINE_ID_KEY, (String) value);
1080                         break;
1081                     case XML_TAG_PRIVATE_KEY_ID:
1082                         enterpriseConfig.setFieldValue(
1083                                 WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, (String) value);
1084                         break;
1085                     case XML_TAG_ALT_SUBJECT_MATCH:
1086                         enterpriseConfig.setFieldValue(
1087                                 WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY, (String) value);
1088                         break;
1089                     case XML_TAG_DOM_SUFFIX_MATCH:
1090                         enterpriseConfig.setFieldValue(
1091                                 WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY, (String) value);
1092                         break;
1093                     case XML_TAG_CA_PATH:
1094                         enterpriseConfig.setFieldValue(
1095                                 WifiEnterpriseConfig.CA_PATH_KEY, (String) value);
1096                         break;
1097                     case XML_TAG_EAP_METHOD:
1098                         enterpriseConfig.setEapMethod((int) value);
1099                         break;
1100                     case XML_TAG_PHASE2_METHOD:
1101                         enterpriseConfig.setPhase2Method((int) value);
1102                         break;
1103                     case XML_TAG_PLMN:
1104                         enterpriseConfig.setPlmn((String) value);
1105                         break;
1106                     case XML_TAG_REALM:
1107                         enterpriseConfig.setRealm((String) value);
1108                         break;
1109                     default:
1110                         throw new XmlPullParserException(
1111                                 "Unknown value name found: " + valueName[0]);
1112                 }
1113             }
1114             return enterpriseConfig;
1115         }
1116     }
1117 }
1118 
1119