Home | History | Annotate | Download | only in wifi
      1 /*
      2  * Copyright (C) 2008 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 android.net.wifi;
     18 
     19 import android.net.LinkProperties;
     20 import android.os.Parcelable;
     21 import android.os.Parcel;
     22 
     23 import java.util.BitSet;
     24 
     25 /**
     26  * A class representing a configured Wi-Fi network, including the
     27  * security configuration. Android will not necessarily support
     28  * all of these security schemes initially.
     29  */
     30 public class WifiConfiguration implements Parcelable {
     31 
     32     /**
     33      * In old configurations, the "private_key" field was used. However, newer
     34      * configurations use the key_id field with the engine_id set to "keystore".
     35      * If this field is found in the configuration, the migration code is
     36      * triggered.
     37      * @hide
     38      */
     39     public static final String OLD_PRIVATE_KEY_NAME = "private_key";
     40 
     41     /**
     42      * String representing the keystore OpenSSL ENGINE's ID.
     43      * @hide
     44      */
     45     public static final String KEYSTORE_ENGINE_ID = "keystore";
     46 
     47     /**
     48      * String representing the keystore URI used for wpa_supplicant.
     49      * @hide
     50      */
     51     public static final String KEYSTORE_URI = "keystore://";
     52 
     53     /**
     54      * String to set the engine value to when it should be enabled.
     55      * @hide
     56      */
     57     public static final String ENGINE_ENABLE = "1";
     58 
     59     /**
     60      * String to set the engine value to when it should be disabled.
     61      * @hide
     62      */
     63     public static final String ENGINE_DISABLE = "0";
     64 
     65     /** {@hide} */
     66     public static final String ssidVarName = "ssid";
     67     /** {@hide} */
     68     public static final String bssidVarName = "bssid";
     69     /** {@hide} */
     70     public static final String pskVarName = "psk";
     71     /** {@hide} */
     72     public static final String[] wepKeyVarNames = { "wep_key0", "wep_key1", "wep_key2", "wep_key3" };
     73     /** {@hide} */
     74     public static final String wepTxKeyIdxVarName = "wep_tx_keyidx";
     75     /** {@hide} */
     76     public static final String priorityVarName = "priority";
     77     /** {@hide} */
     78     public static final String hiddenSSIDVarName = "scan_ssid";
     79     /** {@hide} */
     80     public static final int INVALID_NETWORK_ID = -1;
     81 
     82     /** {@hide} */
     83     public class EnterpriseField {
     84         private String varName;
     85         private String value;
     86 
     87         private EnterpriseField(String varName) {
     88             this.varName = varName;
     89             this.value = null;
     90         }
     91 
     92         public void setValue(String value) {
     93             this.value = value;
     94         }
     95 
     96         public String varName() {
     97             return varName;
     98         }
     99 
    100         public String value() {
    101             return value;
    102         }
    103     }
    104 
    105     /** {@hide} */
    106     public EnterpriseField eap = new EnterpriseField("eap");
    107     /** {@hide} */
    108     public EnterpriseField phase2 = new EnterpriseField("phase2");
    109     /** {@hide} */
    110     public EnterpriseField identity = new EnterpriseField("identity");
    111     /** {@hide} */
    112     public EnterpriseField anonymous_identity = new EnterpriseField("anonymous_identity");
    113     /** {@hide} */
    114     public EnterpriseField password = new EnterpriseField("password");
    115     /** {@hide} */
    116     public EnterpriseField client_cert = new EnterpriseField("client_cert");
    117     /** {@hide} */
    118     public EnterpriseField engine = new EnterpriseField("engine");
    119     /** {@hide} */
    120     public EnterpriseField engine_id = new EnterpriseField("engine_id");
    121     /** {@hide} */
    122     public EnterpriseField key_id = new EnterpriseField("key_id");
    123     /** {@hide} */
    124     public EnterpriseField ca_cert = new EnterpriseField("ca_cert");
    125 
    126     /** {@hide} */
    127     public EnterpriseField[] enterpriseFields = {
    128             eap, phase2, identity, anonymous_identity, password, client_cert,
    129             engine, engine_id, key_id, ca_cert };
    130 
    131     /**
    132      * Recognized key management schemes.
    133      */
    134     public static class KeyMgmt {
    135         private KeyMgmt() { }
    136 
    137         /** WPA is not used; plaintext or static WEP could be used. */
    138         public static final int NONE = 0;
    139         /** WPA pre-shared key (requires {@code preSharedKey} to be specified). */
    140         public static final int WPA_PSK = 1;
    141         /** WPA using EAP authentication. Generally used with an external authentication server. */
    142         public static final int WPA_EAP = 2;
    143         /** IEEE 802.1X using EAP authentication and (optionally) dynamically
    144          * generated WEP keys. */
    145         public static final int IEEE8021X = 3;
    146 
    147         /** WPA2 pre-shared key for use with soft access point
    148           * (requires {@code preSharedKey} to be specified).
    149           * @hide
    150           */
    151         public static final int WPA2_PSK = 4;
    152 
    153         public static final String varName = "key_mgmt";
    154 
    155         public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP", "IEEE8021X",
    156                 "WPA2_PSK" };
    157     }
    158 
    159     /**
    160      * Recognized security protocols.
    161      */
    162     public static class Protocol {
    163         private Protocol() { }
    164 
    165         /** WPA/IEEE 802.11i/D3.0 */
    166         public static final int WPA = 0;
    167         /** WPA2/IEEE 802.11i */
    168         public static final int RSN = 1;
    169 
    170         public static final String varName = "proto";
    171 
    172         public static final String[] strings = { "WPA", "RSN" };
    173     }
    174 
    175     /**
    176      * Recognized IEEE 802.11 authentication algorithms.
    177      */
    178     public static class AuthAlgorithm {
    179         private AuthAlgorithm() { }
    180 
    181         /** Open System authentication (required for WPA/WPA2) */
    182         public static final int OPEN = 0;
    183         /** Shared Key authentication (requires static WEP keys) */
    184         public static final int SHARED = 1;
    185         /** LEAP/Network EAP (only used with LEAP) */
    186         public static final int LEAP = 2;
    187 
    188         public static final String varName = "auth_alg";
    189 
    190         public static final String[] strings = { "OPEN", "SHARED", "LEAP" };
    191     }
    192 
    193     /**
    194      * Recognized pairwise ciphers for WPA.
    195      */
    196     public static class PairwiseCipher {
    197         private PairwiseCipher() { }
    198 
    199         /** Use only Group keys (deprecated) */
    200         public static final int NONE = 0;
    201         /** Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] */
    202         public static final int TKIP = 1;
    203         /** AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] */
    204         public static final int CCMP = 2;
    205 
    206         public static final String varName = "pairwise";
    207 
    208         public static final String[] strings = { "NONE", "TKIP", "CCMP" };
    209     }
    210 
    211     /**
    212      * Recognized group ciphers.
    213      * <pre>
    214      * CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
    215      * TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
    216      * WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key
    217      * WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key (original 802.11)
    218      * </pre>
    219      */
    220     public static class GroupCipher {
    221         private GroupCipher() { }
    222 
    223         /** WEP40 = WEP (Wired Equivalent Privacy) with 40-bit key (original 802.11) */
    224         public static final int WEP40 = 0;
    225         /** WEP104 = WEP (Wired Equivalent Privacy) with 104-bit key */
    226         public static final int WEP104 = 1;
    227         /** Temporal Key Integrity Protocol [IEEE 802.11i/D7.0] */
    228         public static final int TKIP = 2;
    229         /** AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] */
    230         public static final int CCMP = 3;
    231 
    232         public static final String varName = "group";
    233 
    234         public static final String[] strings = { "WEP40", "WEP104", "TKIP", "CCMP" };
    235     }
    236 
    237     /** Possible status of a network configuration. */
    238     public static class Status {
    239         private Status() { }
    240 
    241         /** this is the network we are currently connected to */
    242         public static final int CURRENT = 0;
    243         /** supplicant will not attempt to use this network */
    244         public static final int DISABLED = 1;
    245         /** supplicant will consider this network available for association */
    246         public static final int ENABLED = 2;
    247 
    248         public static final String[] strings = { "current", "disabled", "enabled" };
    249     }
    250 
    251     /** @hide */
    252     public static final int DISABLED_UNKNOWN_REASON                         = 0;
    253     /** @hide */
    254     public static final int DISABLED_DNS_FAILURE                            = 1;
    255     /** @hide */
    256     public static final int DISABLED_DHCP_FAILURE                           = 2;
    257     /** @hide */
    258     public static final int DISABLED_AUTH_FAILURE                           = 3;
    259 
    260     /**
    261      * The ID number that the supplicant uses to identify this
    262      * network configuration entry. This must be passed as an argument
    263      * to most calls into the supplicant.
    264      */
    265     public int networkId;
    266 
    267     /**
    268      * The current status of this network configuration entry.
    269      * @see Status
    270      */
    271     public int status;
    272 
    273     /**
    274      * The code referring to a reason for disabling the network
    275      * Valid when {@link #status} == Status.DISABLED
    276      * @hide
    277      */
    278     public int disableReason;
    279 
    280     /**
    281      * The network's SSID. Can either be an ASCII string,
    282      * which must be enclosed in double quotation marks
    283      * (e.g., {@code "MyNetwork"}, or a string of
    284      * hex digits,which are not enclosed in quotes
    285      * (e.g., {@code 01a243f405}).
    286      */
    287     public String SSID;
    288     /**
    289      * When set, this network configuration entry should only be used when
    290      * associating with the AP having the specified BSSID. The value is
    291      * a string in the format of an Ethernet MAC address, e.g.,
    292      * <code>XX:XX:XX:XX:XX:XX</code> where each <code>X</code> is a hex digit.
    293      */
    294     public String BSSID;
    295 
    296     /**
    297      * Pre-shared key for use with WPA-PSK.
    298      * <p/>
    299      * When the value of this key is read, the actual key is
    300      * not returned, just a "*" if the key has a value, or the null
    301      * string otherwise.
    302      */
    303     public String preSharedKey;
    304     /**
    305      * Up to four WEP keys. Either an ASCII string enclosed in double
    306      * quotation marks (e.g., {@code "abcdef"} or a string
    307      * of hex digits (e.g., {@code 0102030405}).
    308      * <p/>
    309      * When the value of one of these keys is read, the actual key is
    310      * not returned, just a "*" if the key has a value, or the null
    311      * string otherwise.
    312      */
    313     public String[] wepKeys;
    314 
    315     /** Default WEP key index, ranging from 0 to 3. */
    316     public int wepTxKeyIndex;
    317 
    318     /**
    319      * Priority determines the preference given to a network by {@code wpa_supplicant}
    320      * when choosing an access point with which to associate.
    321      */
    322     public int priority;
    323 
    324     /**
    325      * This is a network that does not broadcast its SSID, so an
    326      * SSID-specific probe request must be used for scans.
    327      */
    328     public boolean hiddenSSID;
    329 
    330     /**
    331      * The set of key management protocols supported by this configuration.
    332      * See {@link KeyMgmt} for descriptions of the values.
    333      * Defaults to WPA-PSK WPA-EAP.
    334      */
    335     public BitSet allowedKeyManagement;
    336     /**
    337      * The set of security protocols supported by this configuration.
    338      * See {@link Protocol} for descriptions of the values.
    339      * Defaults to WPA RSN.
    340      */
    341     public BitSet allowedProtocols;
    342     /**
    343      * The set of authentication protocols supported by this configuration.
    344      * See {@link AuthAlgorithm} for descriptions of the values.
    345      * Defaults to automatic selection.
    346      */
    347     public BitSet allowedAuthAlgorithms;
    348     /**
    349      * The set of pairwise ciphers for WPA supported by this configuration.
    350      * See {@link PairwiseCipher} for descriptions of the values.
    351      * Defaults to CCMP TKIP.
    352      */
    353     public BitSet allowedPairwiseCiphers;
    354     /**
    355      * The set of group ciphers supported by this configuration.
    356      * See {@link GroupCipher} for descriptions of the values.
    357      * Defaults to CCMP TKIP WEP104 WEP40.
    358      */
    359     public BitSet allowedGroupCiphers;
    360 
    361     /**
    362      * @hide
    363      */
    364     public enum IpAssignment {
    365         /* Use statically configured IP settings. Configuration can be accessed
    366          * with linkProperties */
    367         STATIC,
    368         /* Use dynamically configured IP settigns */
    369         DHCP,
    370         /* no IP details are assigned, this is used to indicate
    371          * that any existing IP settings should be retained */
    372         UNASSIGNED
    373     }
    374     /**
    375      * @hide
    376      */
    377     public IpAssignment ipAssignment;
    378 
    379     /**
    380      * @hide
    381      */
    382     public enum ProxySettings {
    383         /* No proxy is to be used. Any existing proxy settings
    384          * should be cleared. */
    385         NONE,
    386         /* Use statically configured proxy. Configuration can be accessed
    387          * with linkProperties */
    388         STATIC,
    389         /* no proxy details are assigned, this is used to indicate
    390          * that any existing proxy settings should be retained */
    391         UNASSIGNED
    392     }
    393     /**
    394      * @hide
    395      */
    396     public ProxySettings proxySettings;
    397     /**
    398      * @hide
    399      */
    400     public LinkProperties linkProperties;
    401 
    402     public WifiConfiguration() {
    403         networkId = INVALID_NETWORK_ID;
    404         SSID = null;
    405         BSSID = null;
    406         priority = 0;
    407         hiddenSSID = false;
    408         disableReason = DISABLED_UNKNOWN_REASON;
    409         allowedKeyManagement = new BitSet();
    410         allowedProtocols = new BitSet();
    411         allowedAuthAlgorithms = new BitSet();
    412         allowedPairwiseCiphers = new BitSet();
    413         allowedGroupCiphers = new BitSet();
    414         wepKeys = new String[4];
    415         for (int i = 0; i < wepKeys.length; i++)
    416             wepKeys[i] = null;
    417         for (EnterpriseField field : enterpriseFields) {
    418             field.setValue(null);
    419         }
    420         ipAssignment = IpAssignment.UNASSIGNED;
    421         proxySettings = ProxySettings.UNASSIGNED;
    422         linkProperties = new LinkProperties();
    423     }
    424 
    425     @Override
    426     public String toString() {
    427         StringBuilder sbuf = new StringBuilder();
    428         if (this.status == WifiConfiguration.Status.CURRENT) {
    429             sbuf.append("* ");
    430         } else if (this.status == WifiConfiguration.Status.DISABLED) {
    431             sbuf.append("- DSBLE: ").append(this.disableReason).append(" ");
    432         }
    433         sbuf.append("ID: ").append(this.networkId).append(" SSID: ").append(this.SSID).
    434                 append(" BSSID: ").append(this.BSSID).append(" PRIO: ").append(this.priority).
    435                 append('\n');
    436         sbuf.append(" KeyMgmt:");
    437         for (int k = 0; k < this.allowedKeyManagement.size(); k++) {
    438             if (this.allowedKeyManagement.get(k)) {
    439                 sbuf.append(" ");
    440                 if (k < KeyMgmt.strings.length) {
    441                     sbuf.append(KeyMgmt.strings[k]);
    442                 } else {
    443                     sbuf.append("??");
    444                 }
    445             }
    446         }
    447         sbuf.append(" Protocols:");
    448         for (int p = 0; p < this.allowedProtocols.size(); p++) {
    449             if (this.allowedProtocols.get(p)) {
    450                 sbuf.append(" ");
    451                 if (p < Protocol.strings.length) {
    452                     sbuf.append(Protocol.strings[p]);
    453                 } else {
    454                     sbuf.append("??");
    455                 }
    456             }
    457         }
    458         sbuf.append('\n');
    459         sbuf.append(" AuthAlgorithms:");
    460         for (int a = 0; a < this.allowedAuthAlgorithms.size(); a++) {
    461             if (this.allowedAuthAlgorithms.get(a)) {
    462                 sbuf.append(" ");
    463                 if (a < AuthAlgorithm.strings.length) {
    464                     sbuf.append(AuthAlgorithm.strings[a]);
    465                 } else {
    466                     sbuf.append("??");
    467                 }
    468             }
    469         }
    470         sbuf.append('\n');
    471         sbuf.append(" PairwiseCiphers:");
    472         for (int pc = 0; pc < this.allowedPairwiseCiphers.size(); pc++) {
    473             if (this.allowedPairwiseCiphers.get(pc)) {
    474                 sbuf.append(" ");
    475                 if (pc < PairwiseCipher.strings.length) {
    476                     sbuf.append(PairwiseCipher.strings[pc]);
    477                 } else {
    478                     sbuf.append("??");
    479                 }
    480             }
    481         }
    482         sbuf.append('\n');
    483         sbuf.append(" GroupCiphers:");
    484         for (int gc = 0; gc < this.allowedGroupCiphers.size(); gc++) {
    485             if (this.allowedGroupCiphers.get(gc)) {
    486                 sbuf.append(" ");
    487                 if (gc < GroupCipher.strings.length) {
    488                     sbuf.append(GroupCipher.strings[gc]);
    489                 } else {
    490                     sbuf.append("??");
    491                 }
    492             }
    493         }
    494         sbuf.append('\n').append(" PSK: ");
    495         if (this.preSharedKey != null) {
    496             sbuf.append('*');
    497         }
    498 
    499         for (EnterpriseField field : enterpriseFields) {
    500             sbuf.append('\n').append(" " + field.varName() + ": ");
    501             String value = field.value();
    502             if (value != null) sbuf.append(value);
    503         }
    504         sbuf.append('\n');
    505         sbuf.append("IP assignment: " + ipAssignment.toString());
    506         sbuf.append("\n");
    507         sbuf.append("Proxy settings: " + proxySettings.toString());
    508         sbuf.append("\n");
    509         sbuf.append(linkProperties.toString());
    510         sbuf.append("\n");
    511 
    512         return sbuf.toString();
    513     }
    514 
    515     /**
    516      * Construct a WifiConfiguration from a scanned network
    517      * @param scannedAP the scan result used to construct the config entry
    518      * TODO: figure out whether this is a useful way to construct a new entry.
    519      *
    520     public WifiConfiguration(ScanResult scannedAP) {
    521         networkId = -1;
    522         SSID = scannedAP.SSID;
    523         BSSID = scannedAP.BSSID;
    524     }
    525     */
    526 
    527     private static BitSet readBitSet(Parcel src) {
    528         int cardinality = src.readInt();
    529 
    530         BitSet set = new BitSet();
    531         for (int i = 0; i < cardinality; i++)
    532             set.set(src.readInt());
    533 
    534         return set;
    535     }
    536 
    537     private static void writeBitSet(Parcel dest, BitSet set) {
    538         int nextSetBit = -1;
    539 
    540         dest.writeInt(set.cardinality());
    541 
    542         while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1)
    543             dest.writeInt(nextSetBit);
    544     }
    545 
    546     /** @hide */
    547     public int getAuthType() {
    548         if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
    549             return KeyMgmt.WPA_PSK;
    550         } else if (allowedKeyManagement.get(KeyMgmt.WPA2_PSK)) {
    551             return KeyMgmt.WPA2_PSK;
    552         } else if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
    553             return KeyMgmt.WPA_EAP;
    554         } else if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
    555             return KeyMgmt.IEEE8021X;
    556         }
    557         return KeyMgmt.NONE;
    558     }
    559 
    560     /** Implement the Parcelable interface {@hide} */
    561     public int describeContents() {
    562         return 0;
    563     }
    564 
    565     /** copy constructor {@hide} */
    566     public WifiConfiguration(WifiConfiguration source) {
    567         if (source != null) {
    568             networkId = source.networkId;
    569             status = source.status;
    570             disableReason = source.disableReason;
    571             SSID = source.SSID;
    572             BSSID = source.BSSID;
    573             preSharedKey = source.preSharedKey;
    574 
    575             wepKeys = new String[4];
    576             for (int i = 0; i < wepKeys.length; i++)
    577                 wepKeys[i] = source.wepKeys[i];
    578 
    579             wepTxKeyIndex = source.wepTxKeyIndex;
    580             priority = source.priority;
    581             hiddenSSID = source.hiddenSSID;
    582             allowedKeyManagement   = (BitSet) source.allowedKeyManagement.clone();
    583             allowedProtocols       = (BitSet) source.allowedProtocols.clone();
    584             allowedAuthAlgorithms  = (BitSet) source.allowedAuthAlgorithms.clone();
    585             allowedPairwiseCiphers = (BitSet) source.allowedPairwiseCiphers.clone();
    586             allowedGroupCiphers    = (BitSet) source.allowedGroupCiphers.clone();
    587 
    588             for (int i = 0; i < source.enterpriseFields.length; i++) {
    589                 enterpriseFields[i].setValue(source.enterpriseFields[i].value());
    590             }
    591             ipAssignment = source.ipAssignment;
    592             proxySettings = source.proxySettings;
    593             linkProperties = new LinkProperties(source.linkProperties);
    594         }
    595     }
    596 
    597     /** Implement the Parcelable interface {@hide} */
    598     public void writeToParcel(Parcel dest, int flags) {
    599         dest.writeInt(networkId);
    600         dest.writeInt(status);
    601         dest.writeInt(disableReason);
    602         dest.writeString(SSID);
    603         dest.writeString(BSSID);
    604         dest.writeString(preSharedKey);
    605         for (String wepKey : wepKeys)
    606             dest.writeString(wepKey);
    607         dest.writeInt(wepTxKeyIndex);
    608         dest.writeInt(priority);
    609         dest.writeInt(hiddenSSID ? 1 : 0);
    610 
    611         writeBitSet(dest, allowedKeyManagement);
    612         writeBitSet(dest, allowedProtocols);
    613         writeBitSet(dest, allowedAuthAlgorithms);
    614         writeBitSet(dest, allowedPairwiseCiphers);
    615         writeBitSet(dest, allowedGroupCiphers);
    616 
    617         for (EnterpriseField field : enterpriseFields) {
    618             dest.writeString(field.value());
    619         }
    620         dest.writeString(ipAssignment.name());
    621         dest.writeString(proxySettings.name());
    622         dest.writeParcelable(linkProperties, flags);
    623     }
    624 
    625     /** Implement the Parcelable interface {@hide} */
    626     public static final Creator<WifiConfiguration> CREATOR =
    627         new Creator<WifiConfiguration>() {
    628             public WifiConfiguration createFromParcel(Parcel in) {
    629                 WifiConfiguration config = new WifiConfiguration();
    630                 config.networkId = in.readInt();
    631                 config.status = in.readInt();
    632                 config.disableReason = in.readInt();
    633                 config.SSID = in.readString();
    634                 config.BSSID = in.readString();
    635                 config.preSharedKey = in.readString();
    636                 for (int i = 0; i < config.wepKeys.length; i++)
    637                     config.wepKeys[i] = in.readString();
    638                 config.wepTxKeyIndex = in.readInt();
    639                 config.priority = in.readInt();
    640                 config.hiddenSSID = in.readInt() != 0;
    641                 config.allowedKeyManagement   = readBitSet(in);
    642                 config.allowedProtocols       = readBitSet(in);
    643                 config.allowedAuthAlgorithms  = readBitSet(in);
    644                 config.allowedPairwiseCiphers = readBitSet(in);
    645                 config.allowedGroupCiphers    = readBitSet(in);
    646 
    647                 for (EnterpriseField field : config.enterpriseFields) {
    648                     field.setValue(in.readString());
    649                 }
    650 
    651                 config.ipAssignment = IpAssignment.valueOf(in.readString());
    652                 config.proxySettings = ProxySettings.valueOf(in.readString());
    653                 config.linkProperties = in.readParcelable(null);
    654                 return config;
    655             }
    656 
    657             public WifiConfiguration[] newArray(int size) {
    658                 return new WifiConfiguration[size];
    659             }
    660         };
    661 }
    662